package com.turing.post.cardtransactions.impl;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;

import com.turing.post.account.util.AccountBusiness;
import com.turing.post.account.util.AccountParam;
import com.turing.post.account.util.AccountSystemAddTradDetail;
import com.turing.post.account.util.AccountSystemAddTradDetailDao;
import com.turing.post.account.util.AccountSystemTradDetail;
import com.turing.post.account.util.AccountSystemTradDetailDao;
import com.turing.post.account.util.DepositAccountParam;
import com.turing.post.account.util.DepositAccountResult;
import com.turing.post.account.util.MasterAccount;
import com.turing.post.account.util.MasterAccountDao;
import com.turing.post.account.util.MasterAccountTransferDetail;
import com.turing.post.account.util.MasterAccountTransferDetailDao;
import com.turing.post.account.util.SalesGroup;
import com.turing.post.account.util.SubAccount;
import com.turing.post.account.util.SubAccountDao;
import com.turing.post.capitalaccounts.util.SaleCapitalDetail;
import com.turing.post.capitalaccounts.util.SaleCapitalDetailDao;
import com.turing.post.cardmanagement.util.ActivateCard;
import com.turing.post.cardmanagement.util.ActivateCardDao;
import com.turing.post.cardmanagement.util.CardClassic;
import com.turing.post.cardmanagement.util.CardClassicBindDistrict;
import com.turing.post.cardmanagement.util.CardClassicBindDistrictDao;
import com.turing.post.cardmanagement.util.CardClassicBindMerchant;
import com.turing.post.cardmanagement.util.CardClassicBindMerchantDao;
import com.turing.post.cardmanagement.util.CardClassicDao;
import com.turing.post.cardmanagement.util.CardEventLog;
import com.turing.post.cardmanagement.util.CardEventLogDao;
import com.turing.post.cardmanagement.util.CardLoss;
import com.turing.post.cardmanagement.util.CardLossDao;
import com.turing.post.cardmanagement.util.CardManaRespCode;
import com.turing.post.cardmanagement.util.CardStock;
import com.turing.post.cardmanagement.util.CardStockDao;
import com.turing.post.cardmanagement.util.MakeCardControl;
import com.turing.post.cardmanagement.util.MakeCardControlDao;
import com.turing.post.cardmanagement.util.SaleCardStockDetail;
import com.turing.post.cardmanagement.util.SaleCardStockDetailDao;
import com.turing.post.cardtransactions.util.CardAccountDetail;
import com.turing.post.cardtransactions.util.CardAccountParam;
import com.turing.post.cardtransactions.util.CardLossObject;
import com.turing.post.cardtransactions.util.CardMagneticObject;
import com.turing.post.cardtransactions.util.CardOwnerObject;
import com.turing.post.cardtransactions.util.CardTranApplicationException;
import com.turing.post.cardtransactions.util.CardTransBusiness;
import com.turing.post.cardtransactions.util.CashDepositObject;
import com.turing.post.cardtransactions.util.ChangeCardClassicObject;
import com.turing.post.cardtransactions.util.ExtendExpiredObject;
import com.turing.post.cardtransactions.util.FreezeAccountObject;
import com.turing.post.cardtransactions.util.IssueNewCardObject;
import com.turing.post.cardtransactions.util.MrchDepositObject;
import com.turing.post.cardtransactions.util.PaidParam;
import com.turing.post.cardtransactions.util.PaidParam.PaidCardParam;
import com.turing.post.cardtransactions.util.PaidResult;
import com.turing.post.cardtransactions.util.RedempObject;
import com.turing.post.cardtransactions.util.ResetPasswordObject;
import com.turing.post.common.util.PCPSCommonDao;
import com.turing.post.common.util.SysOpUser;
import com.turing.post.common.util.SysOpUserDao;
import com.turing.post.common.util.SysOperLog;
import com.turing.post.common.util.SysOperLogDao;
import com.turing.post.organization.util.BusinessDistrict;
import com.turing.post.organization.util.BusinessDistrictDao;
import com.turing.post.organization.util.BusinessDistrictMerchant;
import com.turing.post.organization.util.BusinessDistrictMerchantDao;
import com.turing.post.organization.util.CreditAccDetail;
import com.turing.post.organization.util.IssueBranch;
import com.turing.post.organization.util.IssueBranchBusiness;
import com.turing.post.organization.util.IssueBranchDao;
import com.turing.post.organization.util.IssueCompany;
import com.turing.post.organization.util.IssueCompanyDao;
import com.turing.post.organization.util.IssueFeePolicy;
import com.turing.post.organization.util.IssueFeePolicyBusiness;
import com.turing.post.organization.util.IssueFeePolicyLimit;
import com.turing.post.organization.util.IssueFeePolicyLimitDao;
import com.turing.post.organization.util.Merchant;
import com.turing.post.organization.util.MerchantDao;
import com.turing.post.organization.util.SaleBranch;
import com.turing.post.organization.util.SaleBranchDao;
import com.turing.post.organization.util.SysBranch;
import com.turing.post.organization.util.SysBranchDao;
import com.turing.post.organization.util.VoucherBusinessBind;
import com.turing.post.organization.util.VoucherBusinessBindDao;
import com.turing.post.organization.util.VoucherStock;
import com.turing.post.organization.util.VoucherStockDao;
import com.turing.post.organization.util.VoucherStockDetail;
import com.turing.post.organization.util.VoucherStockDetailDao;
import com.turing.post.salesmanage.util.DepositOrder;
import com.turing.post.salesmanage.util.DepositOrderActionDetail;
import com.turing.post.salesmanage.util.DepositOrderActionDetailDao;
import com.turing.post.salesmanage.util.DepositOrderDao;
import com.turing.post.salesmanage.util.DepositOrderDetail;
import com.turing.post.salesmanage.util.DepositOrderDetailDao;
import com.turing.post.salesmanage.util.DepositOrderPaidDetail;
import com.turing.post.salesmanage.util.DepositOrderPaidDetailDao;
import com.turing.post.salesmanage.util.DepositOrderSalesDetail;
import com.turing.post.salesmanage.util.DepositOrderSalesDetailDao;
import com.turing.post.salesmanage.util.PersonalCustom;
import com.turing.post.salesmanage.util.PersonalCustomDao;
import com.turing.post.salesmanage.util.RedempOrder;
import com.turing.post.salesmanage.util.RedempOrderActionDetail;
import com.turing.post.salesmanage.util.RedempOrderActionDetailDao;
import com.turing.post.salesmanage.util.RedempOrderDao;
import com.turing.post.salesmanage.util.RedempOrderDetail;
import com.turing.post.salesmanage.util.RedempOrderDetailDao;
import com.turing.post.salesmanage.util.SaleOrder;
import com.turing.post.salesmanage.util.SaleOrderDao;
import com.turing.post.tuxedo.util.TuxedoRespCode;
import com.turing.post.util.PCPSApplicationException;
import com.turing.post.util.PCPSUtil;
import com.turing.post.util.PCPSWebInput;
import com.turing.post.util.SHA1;

/**
 * 实现诸如查询余额、改密码、交易前检查、支付/取消等业务逻辑
 * 
 * @author yxb
 */
@Stateless(mappedName = "cardtransactions.impl.CardTransBusinessImpl")
@Remote
@Local
public class CardTransBusinessImpl implements CardTransBusiness {

	@EJB(mappedName = "common.impl.PCPSCommonDaoImpl")
	private PCPSCommonDao pcpsCommonDaoImpl;

	@EJB(mappedName = "organization.impl.SysBranchDaoImpl")
	private SysBranchDao sysBranchDaoImpl;

	@EJB(mappedName = "cardmanagement.impl.ActivateCardDaoImpl")
	private ActivateCardDao activateCardDaoImpl;

	@EJB(mappedName = "cardmanagement.impl.MakeCardControlDaoImpl")
	private MakeCardControlDao makeCardControlDaoImpl;

	@EJB(mappedName = "cardmanagement.impl.CardClassicBindMerchantDaoImpl")
	private CardClassicBindMerchantDao cardClassicBindMerchantDaoImpl;

	@EJB(mappedName = "cardmanagement.impl.CardClassicBindDistrictDaoImpl")
	private CardClassicBindDistrictDao cardClassicBindDistrictDaoImpl;

	@EJB(mappedName = "organization.impl.BusinessDistrictMerchantDaoImpl")
	private BusinessDistrictMerchantDao businessDistrictMerchantDaoImpl;

	@EJB(mappedName = "organization.impl.IssueCompanyDaoImpl")
	private IssueCompanyDao issueCompanyDaoImpl;

	@EJB(mappedName = "cardmanagement.impl.CardEventLogDaoImpl")
	private CardEventLogDao cardEventLogDaoImpl;

	@EJB(mappedName = "account.impl.MasterAccountDaoImpl")
	private MasterAccountDao masterAccountDaoImpl;

	@EJB(mappedName = "account.impl.SubAccountDaoImpl")
	private SubAccountDao subAccountDaoImpl;

	@EJB(mappedName = "organization.impl.MerchantDaoImpl")
	private MerchantDao merchantDaoImpl;

	@EJB(mappedName = "cardmanagement.impl.CardClassicDaoImpl")
	private CardClassicDao cardClassicDaoImpl;

	@EJB(mappedName = "account.impl.AccountBusinessImpl")
	private AccountBusiness accountBusinessImpl;

	@EJB(mappedName = "account.impl.AccountSystemAddTradDetailDaoImpl")
	private AccountSystemAddTradDetailDao accountSystemAddTradDetailDaoImpl;

	@EJB(mappedName = "salesmanage.impl.SaleOrderDaoImpl")
	private SaleOrderDao saleOrderDaoImpl;

	@EJB(mappedName = "common.impl.SysOpUserDaoImpl")
	private SysOpUserDao sysOpUserDaoImpl;

	@EJB(mappedName = "organization.impl.SaleBranchDaoImpl")
	private SaleBranchDao saleBranchDaoImpl;

	@EJB(mappedName = "salesmanage.impl.DepositOrderDaoImpl")
	private DepositOrderDao depositOrderDaoImpl;

	@EJB(mappedName = "salesmanage.impl.DepositOrderDetailDaoImpl")
	private DepositOrderDetailDao depositOrderDetailDaoImpl;

	@EJB(mappedName = "salesmanage.impl.DepositOrderSalesDetailDaoImpl")
	private DepositOrderSalesDetailDao depositOrderSalesDetailDaoImpl;

	@EJB(mappedName = "salesmanage.impl.DepositOrderPaidDetailDaoImpl")
	private DepositOrderPaidDetailDao depositOrderPaidDetailDaoImpl;

	@EJB(mappedName = "salesmanage.impl.DepositOrderActionDetailDaoImpl")
	private DepositOrderActionDetailDao depositOrderActionDetailDaoImpl;

	@EJB(mappedName = "capitalaccounts.impl.SaleCapitalDetailDaoImpl")
	private SaleCapitalDetailDao saleCapitalDetailDaoImpl;

	@EJB(mappedName = "account.impl.AccountSystemTradDetailDaoImpl")
	private AccountSystemTradDetailDao accountSystemTradDetailDaoImpl;

	@EJB(mappedName = "cardmanagement.impl.CardStockDaoImpl")
	private CardStockDao cardStockDaoImpl;

	@EJB(mappedName = "cardmanagement.impl.SaleCardStockDetailDaoImpl")
	private SaleCardStockDetailDao saleCardStockDetailDaoImpl;

	@EJB(mappedName = "salesmanage.impl.RedempOrderDaoImpl")
	private RedempOrderDao redempOrderDaoImpl;

	@EJB(mappedName = "account.impl.MasterAccountTransferDetailDaoImpl")
	private MasterAccountTransferDetailDao masterAccountTransferDetailDaoImpl;

	@EJB(mappedName = "salesmanage.impl.RedempOrderDetailDaoImpl")
	private RedempOrderDetailDao redempOrderDetailDaoImpl;

	@EJB(mappedName = "salesmanage.impl.RedempOrderActionDetailDaoImpl")
	private RedempOrderActionDetailDao redempOrderActionDetailDaoImpl;

	@EJB(mappedName = "organization.impl.IssueFeePolicyBusinessImpl")
	private IssueFeePolicyBusiness issueFeePolicyBusinessImpl;

	@EJB(mappedName = "salesmanage.impl.PersonalCustomDaoImpl")
	private PersonalCustomDao personalCustomDao;

	@EJB(mappedName = "cardmanagement.impl.CardLossDaoImpl")
	private CardLossDao cardLossDao;

	@EJB(mappedName = "organization.impl.VoucherBusinessBindDaoImpl")
	private VoucherBusinessBindDao voucherBusinessBindImpl;

	@EJB(mappedName = "organization.impl.VoucherStockDaoImpl")
	private VoucherStockDao voucherStockDaoImpl;

	@EJB(mappedName = "organization.impl.VoucherStockDetailDaoImpl")
	private VoucherStockDetailDao voucherStockDetailDaoImpl;

	@EJB(mappedName = "organization.impl.IssueBranchBusinessImpl")
	private IssueBranchBusiness issueBranchBusinessImpl;

	@EJB(mappedName = "common.impl.SysOperLogDaoImpl")
	private SysOperLogDao sysOperLogDaoImpl;

	@EJB(mappedName = "organization.impl.BusinessDistrictDaoImpl")
	private BusinessDistrictDao businessDistrictDaoImpl;

	@EJB(mappedName = "organization.impl.IssueFeePolicyLimitDaoImpl")
	private IssueFeePolicyLimitDao issueFeePolicyLimitDaoImpl;

	@EJB(mappedName = "organization.impl.IssueBranchDaoImpl")
	private IssueBranchDao issueBranchDaoImpl;

	/**
	 * 异常抛出方法
	 * 
	 * @param error
	 * @throws PCPSApplicationException
	 */
	private void errException(String error) throws PCPSApplicationException {
		throw new CardTranApplicationException(CardManaRespCode.RC_ARGS_NULL,
				"", error);
	}

	/**
	 * 获取实际费用,如果按资费策略计算的费用超过发卡商的上下限,则取发卡商的上下限
	 * 
	 * @param issueCompanyNo
	 * @param fee
	 * @param tranCode
	 * @return
	 */
	private BigInteger getIssuePolicyLimitFee(String issueCompanyNo,
			BigInteger fee, String tranCode) {
		// 取发卡商资费上下限
		IssueFeePolicyLimit ifpl = issueFeePolicyLimitDaoImpl
				.getIssueFeePolicyLimitByCompNoAndTypeForEffective(
						issueCompanyNo, tranCode);
		if (ifpl != null) {
			// 上限
			if (ifpl.getFeeUpperLimit().compareTo(BigInteger.ZERO) > 0) {
				if (fee.compareTo(ifpl.getFeeUpperLimit()) > 0) {
					fee = ifpl.getFeeUpperLimit();
				}
			}
			// 下限
			if (ifpl.getFeeLowerLimit().compareTo(BigInteger.ZERO) > 0) {
				if (fee.compareTo(ifpl.getFeeLowerLimit()) < 0) {
					fee = ifpl.getFeeLowerLimit();
				}
			}
		}
		return fee;
	}

	/**
	 * 检查当前操作机构是否处于日终状态
	 * 
	 * @param branchNo
	 * @throws PCPSApplicationException
	 */
	private SaleBranch checkSaleBranchDayOff(String branchNo)
			throws PCPSApplicationException {
		if (PCPSUtil.isEmpty(branchNo)) {
			errException("无效的销售机构号码!");
		}
		SaleBranch sb = saleBranchDaoImpl.getSaleBranchBySaleBranchNo(branchNo);
		if (sb == null) {
			errException("销售机构机构信息未获取到!");
		}
		if (SaleBranch.In_DayOff.equals(sb.getDayOff())) {
			errException("销售机构已日结，禁止办理业务!");
		}
		return sb;
	}

	/**
	 * 校验手续费优惠授权操作员
	 * 
	 * @param authOperId
	 * @param pwd
	 * @param operId
	 * @param branchNo
	 * @throws PCPSApplicationException
	 */
	private void checkAuthOperId(BigInteger authOperId, String authPwd,
			BigInteger operId, String branchNo) throws PCPSApplicationException {
		if (authOperId == null || PCPSUtil.isEmpty(authPwd)) {
			errException("无效的授权操作员或密码!");
		}
		SysOpUser su = sysOpUserDaoImpl.getSysOpUserByOperId(authOperId);
		if (su == null) {
			errException("主管授权用户不存在!");
		}
		if (su.getOperId().compareTo(operId) == 0) {
			errException("主管授权用户不能为当前操作用户!");
		}
		String password = new SHA1()
				.getDigestOfString((su.getOperLogonName() + authPwd).getBytes());
		if (!su.getOperPasswd().equals(password)) {
			errException("主管授权密码错误!");
		}
	}

	/**
	 * 检查卡余额是否超过限制
	 * 
	 * @param cardNo
	 * @param newbal
	 * @param issueCompany
	 * @param cardClassic
	 * @throws PCPSApplicationException
	 */
	private void checkBalanceLimit(String cardNo, BigInteger newbal,
			IssueCompany issueCompany, CardClassic cardClassic)
			throws PCPSApplicationException {
		BigInteger ballim = cardClassic.getBalanceLimit();
		int result = BigInteger.ZERO.compareTo(ballim);
		if (result > 0)
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡种类[" + cardClassic.getCardClassicName() + "]余额限制参数非法!");
		if (result == 0)
			ballim = issueCompany.getEachCardBalanceLimit();

		result = BigInteger.ZERO.compareTo(ballim);
		if (result > 0)
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"发卡商[" + issueCompany.getIssueCompanyNo() + "]余额限制参数非法!");
		if (result == 0)
			return;

		if (newbal.compareTo(ballim) > 0)
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡号[" + cardNo + "]余额/交易后余额超过系统限制!");
	}

	/**
	 * 获得有效的激活卡
	 * 
	 * @param cardNo
	 * @return
	 * @throws PCPSApplicationException
	 */
	private ActivateCard getValidateActivateCardByCardNo(String cardNo)
			throws PCPSApplicationException {
		if (PCPSUtil.isEmpty(cardNo))
			throw new PCPSApplicationException(
					PCPSApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID, "卡号为NULL");
		ActivateCard ac = activateCardDaoImpl.getActivateCardByCardNo(cardNo);
		if (ac == null) {
			PCPSUtil.Log("卡号" + cardNo + "不存在!");
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡号" + cardNo + "不存在!");
		}

		return ac;
	}

	/**
	 * 记载卡日志 -- 主事务内部
	 * 
	 * @param cardNo
	 * @param occurTime
	 * @param eventType
	 * @param operId
	 * @param remark
	 * @throws PCPSApplicationException
	 */
	private BigInteger insertCardEventLog(String cardNo, Date occurTime,
			Date tranDate, String cardEventOrderSeq, String eventType,
			BigInteger operId, String remark) throws PCPSApplicationException {
		CardEventLog cel = new CardEventLog();
		BigInteger eventId = pcpsCommonDaoImpl.getUniqueIntegerKey();
		cel.setCardEventId(eventId);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(cardNo);
		cel.setEventType(eventType);
		cel.setTranTime(occurTime);
		cel.setOperId(operId);
		cel.setRemark(remark);
		SysOpUser sysOpUser = sysOpUserDaoImpl.getSysOpUserByOperId(operId);
		if (sysOpUser != null) {
			cel.setBranchNo(sysOpUser.getOperBranchNo());
		}
		ActivateCard ac = activateCardDaoImpl.getActivateCardByCardNo(cardNo);
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(ac.getBatchNo());

		if (tranDate == null) {
			IssueCompany ic = issueCompanyDaoImpl
					.getIssueCompanyByIssueCompanyNo(ac.getBatchNo().substring(
							0, 6));
			tranDate = ic.getTranDate();
		}
		cel.setExpired(ac.getExpired());
		cel.setBalance(ac.getBalance());
		cel.setFee(BigInteger.ZERO);
		cel.setCashFee(BigInteger.ZERO);
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setTranDate(tranDate);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(mcc.getIssueCompanyNo());

		cardEventLogDaoImpl.insert(cel);
		return eventId;
	}

	private BigInteger cardTransCreateCardEventLog(String cardNo,
			Date occurTime, String eventType, BigInteger operId, String remark)
			throws PCPSApplicationException {
		CardEventLog cel = new CardEventLog();
		BigInteger eventId = pcpsCommonDaoImpl.getUniqueIntegerKey();
		cel.setCardEventId(eventId);
		cel.setCardNo(cardNo);
		cel.setEventType(eventType);
		cel.setTranTime(occurTime);
		cel.setOperId(operId);
		cel.setRemark(remark);

		ActivateCard ac = activateCardDaoImpl.getActivateCardByCardNo(cardNo);
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(ac.getBatchNo());

		cel.setBalance(ac.getBalance());
		cel.setFee(BigInteger.ZERO);
		cel.setCashFee(BigInteger.ZERO);
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setTranDate(occurTime);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(mcc.getIssueCompanyNo());

		cardEventLogDaoImpl.insert(cel);
		return eventId;
	}

	/**
	 * 记载卡特殊日志 -- 单独的事务
	 * 
	 * @param cardNo
	 * @param eventType
	 * @param operId
	 * @param remark
	 */
	@TransactionAttribute(javax.ejb.TransactionAttributeType.REQUIRES_NEW)
	private void createCardEventLog(String cardNo, Date occurTime,
			String eventType, BigInteger operId, String remark) {
		try {
			cardTransCreateCardEventLog(cardNo, occurTime, eventType, operId,
					remark);
		} catch (Exception e) {
		}
	}

	/**
	 * 修改卡密码
	 * 
	 * @param webInput
	 * @param rpObj
	 * @return
	 * @throws PCPSApplicationException
	 */
	public String ChangePassword(String cardNo, String oldPwd, String newPwd,
			BigInteger operId, String remark) throws PCPSApplicationException {
		// 1. 参数检查
		if (PCPSUtil.isEmpty(cardNo) || PCPSUtil.isEmpty(oldPwd)
				|| PCPSUtil.isEmpty(newPwd) || PCPSUtil.isEmpty(remark)
				|| operId == null)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);

		// 2. 检查新密码的有效性
		if (!ActivateCard.CheckPassword(newPwd))
			throw new CardTranApplicationException(TuxedoRespCode.RC_NPWDERR,
					"新密码无效!");

		// 3. 检查卡相关属性
		ActivateCard ac = chkCardAttribute(cardNo, oldPwd, null);

		// 检查新密码和旧密码是否相同
		String newPassWord = new com.turing.post.util.SHA1()
				.getDigestOfString((cardNo + newPwd).getBytes());
		if (ac.getCardPwd().equals(newPassWord)) {
			throw new CardTranApplicationException(TuxedoRespCode.RC_NPWDERR,
					"新密码不能和旧密码相同!");
		}
		// 检查是否能交易
		isCardCanDoTrans(ac);

		// 取当前时间
		Date occurTime = pcpsCommonDaoImpl.getDatabaseSysTime();

		// 产生单号
		Integer seqNo = 0;
		String cardEventOrderSeq = "TRAN";

		Date tranDate = null;
		// 2013.05.10 modify by yxb
		if (operId != null) {
			SysOpUser sysOpUser = sysOpUserDaoImpl.getSysOpUserByOperId(operId);
			if (sysOpUser == null
					|| PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
				throw new CardTranApplicationException("", "", "操作员无效!");
			// 单号
			seqNo = sysBranchDaoImpl.updateSysBranchOrderSeqNo(sysOpUser
					.getOperBranchNo());
			// 取发卡商信息
			IssueCompany issueCompany = issueCompanyDaoImpl
					.getIssueCompanyByIssueCompanyNo(PCPSUtil
							.getICNoByBranchNo(sysOpUser.getOperBranchNo()));
			cardEventOrderSeq = sysOpUser.getOperBranchNo()
					+ PCPSUtil.getPackedYMDString(issueCompany.getTranDate())
					+ String.format("%05d", seqNo);
			tranDate = issueCompany.getTranDate();
			// 日志记录
			PCPSWebInput webInput = new PCPSWebInput();
			webInput.setOperId(operId);
			sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
					SysOperLog.operType_Add, "根据卡号修改密码", "CardNo: " + cardNo);
		}

		// 4. 记载日志
		BigInteger cardEventLogId = insertCardEventLog(cardNo, occurTime,
				tranDate, cardEventOrderSeq,
				CardEventLog.CARDEVENTLOG_EVENTTYPE_CHANGE_PASSWORD, operId,
				remark);

		// 5. 执行密码修改
		ac.ChangePassword(newPwd);
		activateCardDaoImpl.update(ac);

		return cardEventLogId.toString();
	}

	/**
	 * 修改卡密码(收费)
	 * 
	 * @param webInput
	 * @param rpObj
	 * @return
	 * @throws PCPSApplicationException
	 */
	public ResetPasswordObject ChangePasswordCharge(PCPSWebInput webInput,
			ResetPasswordObject rpObj) throws PCPSApplicationException {
		// 1. 参数检查
		if (rpObj == null || PCPSUtil.isEmpty(rpObj.cardNo)
				|| rpObj.operId == null)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);

		// 检查销售机构日终状态
		checkSaleBranchDayOff(webInput.getOperBranchNo());

		// 2. 检查新密码的有效性
		if (!ActivateCard.CheckPassword(rpObj.newPwd))
			throw new CardTranApplicationException("旧密码无效!");

		// 3. 检查卡相关属性
		ActivateCard ac = chkCardAttribute(rpObj.cardNo, rpObj.oldPwd, null);

		// 检查是否能交易
		isCardCanDoTrans(ac);

		// 取当前时间
		Date occurTime = pcpsCommonDaoImpl.getDatabaseSysTime();
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(rpObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new CardTranApplicationException("", "", "操作员无效!");

		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(PCPSUtil
						.getICNoByBranchNo(sysOpUser.getOperBranchNo()));

		// 计算费用
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_modifyPasswd, ac.getCardNo(),
				null, issueCompany.getTranDate(), ac.getBalance());
		BigInteger fee = ifp.getFee();

		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_modifyPasswd);

		// 设置返回余额
		rpObj.balance = ac.getBalance();
		rpObj.fee = fee;

		// 如果是试算,把试算结果返回
		if (rpObj.isTrail) {
			return rpObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !rpObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}

		// 检查必要的参数
		if (PCPSUtil.isEmpty(rpObj.newPwd) || PCPSUtil.isEmpty(rpObj.remark))
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);

		// 检查收费模式
		if (!PCPSUtil.compareObject(rpObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(rpObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");

		// 检查优惠的手续费
		if ((rpObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(rpObj.discountFee) > 0
				|| rpObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (rpObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(rpObj.authOperId, rpObj.authPwd, rpObj.operId,
					sysOpUser.getOperBranchNo());
		else
			rpObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(rpObj.discountFee);

		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(rpObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			rpObj.cashFee = BigInteger.ZERO;
			rpObj.cardFee = factfee;
		} else {
			rpObj.cashFee = factfee;
			rpObj.cardFee = BigInteger.ZERO;
		}

		// 检查新密码和旧密码是否相同
		String newPassWord = new com.turing.post.util.SHA1()
				.getDigestOfString((rpObj.cardNo + rpObj.newPwd).getBytes());
		if (ac.getCardPwd().equals(newPassWord)) {
			throw new CardTranApplicationException(TuxedoRespCode.RC_NPWDERR,
					"新密码不能和旧密码相同!");
		}

		// 5.修改密码
		ac.ChangePassword(rpObj.newPwd);
		activateCardDaoImpl.update(ac);

		// 卡事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		String accSeqNo = null;

		// 如果需要延期,则执行扣费动作
		if (rpObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = rpObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = rpObj.cardNo;
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = rpObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "修改卡密码手续费");

			// 保留流水号
			accSeqNo = paidResult.accseqno;

			// 设置返回余额
			rpObj.balance = paidResult.cardbalance.get(rpObj.cardNo);
		}

		// 现金收入记帐
		if (rpObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					rpObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid, rpObj.operId,
					occurTime, "修改卡密码手续费");

		// 单号
		Integer seqNo = sysBranchDaoImpl.updateSysBranchOrderSeqNo(sysOpUser
				.getOperBranchNo());
		String cardEventOrderSeq = sysOpUser.getOperBranchNo()
				+ PCPSUtil.getPackedYMDString(issueCompany.getTranDate())
				+ String.format("%05d", seqNo);
		rpObj.orderSeqNo = evid.toString();// 返回的CardEventId
		// 记载卡延期事件日志
		CardEventLog cel = new CardEventLog();

		cel.setBalance(rpObj.balance);
		cel.setFee(fee);
		cel.setCardFee(rpObj.cardFee);
		cel.setCashFee(rpObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(rpObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(rpObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(rpObj.operId);
		cel.setRemark(rpObj.remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(ac.getCardNo());
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setExpired(ac.getExpired());
		cel.setNewExpired(null);
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(occurTime);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_CHANGE_PASSWORD);

		cardEventLogDaoImpl.insert(cel);
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Add, "修改卡密码", "CardNo: " + ac.getCardNo());

		return rpObj;
	}

	/**
	 * 重置密码
	 * 
	 * @param rpObj
	 * @return
	 * @throws PCPSApplicationException
	 */
	public ResetPasswordObject ResetPassword(PCPSWebInput webInput,
			ResetPasswordObject rpObj) throws PCPSApplicationException {
		// 1. 参数检查
		if (rpObj == null || PCPSUtil.isEmpty(rpObj.cardNo)
				|| rpObj.operId == null)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);

		// 2. 检查新密码的有效性
		if (!ActivateCard.CheckPassword(rpObj.newPwd))
			throw new CardTranApplicationException(TuxedoRespCode.RC_NPWDERR,
					"新密码无效!");

		// 3. 检查卡相关属性
		ActivateCard ac = chkCardAttribute(rpObj.cardNo, null, null);

		// 检查是否能交易
		isCardCanDoTrans(ac);
		// 检查销售机构日终状态
		checkSaleBranchDayOff(webInput.getOperBranchNo());
		// 取当前时间
		Date occurTime = pcpsCommonDaoImpl.getDatabaseSysTime();

		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(rpObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new CardTranApplicationException("", "", "操作员无效!");

		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(PCPSUtil
						.getICNoByBranchNo(sysOpUser.getOperBranchNo()));

		// 计算费用
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_resetPasswd, ac.getCardNo(),
				null, issueCompany.getTranDate(), ac.getBalance());
		BigInteger fee = ifp.getFee();

		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_resetPasswd);

		// 设置返回余额
		rpObj.balance = ac.getBalance();
		rpObj.fee = fee;

		// 如果是试算,把试算结果返回
		if (rpObj.isTrail) {
			return rpObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !rpObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}

		// 检查必要的参数
		if (PCPSUtil.isEmpty(rpObj.newPwd) || PCPSUtil.isEmpty(rpObj.remark))
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);

		// 检查收费模式
		if (!PCPSUtil.compareObject(rpObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(rpObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");

		// 检查优惠的手续费
		if ((rpObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(rpObj.discountFee) > 0
				|| rpObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (rpObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(rpObj.authOperId, rpObj.authPwd, rpObj.operId,
					sysOpUser.getOperBranchNo());
		else
			rpObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(rpObj.discountFee);

		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(rpObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			rpObj.cashFee = BigInteger.ZERO;
			rpObj.cardFee = factfee;
		} else {
			rpObj.cashFee = factfee;
			rpObj.cardFee = BigInteger.ZERO;
		}

		// 5. 执行密码修改
		ac.ChangePassword(rpObj.newPwd);
		activateCardDaoImpl.update(ac);

		// 卡事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		String accSeqNo = null;

		// 如果需要延期,则执行扣费动作
		if (rpObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = rpObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = rpObj.cardNo;
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = rpObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "密码重置手续费");

			// 保留流水号
			accSeqNo = paidResult.accseqno;

			// 设置返回余额
			rpObj.balance = paidResult.cardbalance.get(rpObj.cardNo);
		}

		// 现金收入记帐
		if (rpObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					rpObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid, rpObj.operId,
					occurTime, "密码重置手续费");

		// 单号
		Integer seqNo = sysBranchDaoImpl.updateSysBranchOrderSeqNo(sysOpUser
				.getOperBranchNo());
		String cardEventOrderSeq = sysOpUser.getOperBranchNo()
				+ PCPSUtil.getPackedYMDString(issueCompany.getTranDate())
				+ String.format("%05d", seqNo);
		rpObj.orderSeqNo = evid.toString();// 返回的CardEventId
		// 记载卡延期事件日志
		CardEventLog cel = new CardEventLog();

		cel.setBalance(rpObj.balance);
		cel.setFee(fee);
		cel.setCardFee(rpObj.cardFee);
		cel.setCashFee(rpObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(rpObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(rpObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(rpObj.operId);
		cel.setRemark(rpObj.remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(ac.getCardNo());
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setExpired(ac.getExpired());
		cel.setNewExpired(null);
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(occurTime);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_RESET_PASSWORD);

		cardEventLogDaoImpl.insert(cel);
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Add, "重置密码", "CardNo: " + ac.getCardNo());

		return rpObj;
	}

	/**
	 * 登记或变更实名信息
	 * 
	 * @param coObj
	 * @return
	 * @throws PCPSApplicationException
	 */
	@Override
	public CardOwnerObject cardAssociateOwnerId(PCPSWebInput webInput,
			CardOwnerObject coObj) throws PCPSApplicationException {
		// 1. 参数检查
		if (coObj == null || PCPSUtil.isEmpty(coObj.cardNo)
				|| coObj.operId == null || coObj.newOperId == null)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		// 如果是执行业务操作,检查备注是否为空
		if (!coObj.isTrail && PCPSUtil.isEmpty(coObj.remark)) {
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		}
		// 2. 检查登记/变更人是否为空
		PersonalCustom pcObj = personalCustomDao
				.getPersonalCustomByPersonalId(coObj.newOperId);
		if (pcObj == null) {
			errException("登记或变更的卡持有人未找到!");
		}
		// 3. 检查卡相关属性
		ActivateCard ac = chkCardAttribute(coObj.cardNo, null, null);
		// 检查是否能交易
		isCardCanDoTrans(ac);
		// 检查销售机构日终状态
		checkSaleBranchDayOff(webInput.getOperBranchNo());
		// 取当前时间
		Date occurTime = pcpsCommonDaoImpl.getDatabaseSysTime();

		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(coObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo())) {
			errException("操作员无效!");
		}
		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(PCPSUtil
						.getICNoByBranchNo(sysOpUser.getOperBranchNo()));
		String sql = "";
		// 计算费用
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_realName, ac.getCardNo(),
				null, issueCompany.getTranDate(), ac.getBalance());

		BigInteger fee = ifp.getFee();

		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_realName);

		// 设置返回余额
		coObj.balance = ac.getBalance();
		coObj.fee = fee;

		// 如果是试算,把试算结果返回
		if (coObj.isTrail) {
			return coObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !coObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}

		// 检查收费模式
		if (!PCPSUtil.compareObject(coObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(coObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");

		// 检查优惠的手续费
		if ((coObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(coObj.discountFee) > 0
				|| coObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (coObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(coObj.authOperId, coObj.authPwd, coObj.operId,
					sysOpUser.getOperBranchNo());
		else
			coObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(coObj.discountFee);

		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(coObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			coObj.cashFee = BigInteger.ZERO;
			coObj.cardFee = factfee;
		} else {
			coObj.cashFee = factfee;
			coObj.cardFee = BigInteger.ZERO;
		}

		// 执行变更持卡人操作:判断卡是否有实名信息.持卡人为空时登记
		if (ac.getOwnerId() == null) {
			// 登记新持卡人
			sql = "update ActivateCard set OwnerId=" + coObj.newOperId
					+ ",Expired=null where CardNo='" + ac.getCardNo() + "'";
			activateCardDaoImpl.setTableFieldIsNull(sql);
		} else if (!ac.getOwnerId().equals(coObj.newOperId)) {
			// 变更持卡人和旧持卡人不一致
			errException("卡持有人和变更后持卡人不一致!");
		}

		// 卡事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		String accSeqNo = null;

		// 如果需要延期,则执行扣费动作
		if (coObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = coObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = coObj.cardNo;
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = coObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "登记或变更实名信息手续费");

			// 保留流水号
			accSeqNo = paidResult.accseqno;

			// 设置返回余额
			coObj.balance = paidResult.cardbalance.get(coObj.cardNo);
		}

		// 现金收入记帐
		if (coObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					coObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid, coObj.operId,
					occurTime, "登记或变更实名信息手续费");

		String cardEventOrderSeq = pcpsCommonDaoImpl.getOrderNumber(occurTime,
				coObj.branchNo);

		coObj.orderSeqNo = evid.toString();// 返回的CardEventId
		// 记载卡事件日志
		CardEventLog cel = new CardEventLog();

		cel.setBalance(coObj.balance);
		cel.setFee(fee);
		cel.setCardFee(coObj.cardFee);
		cel.setCashFee(coObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(coObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(coObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(coObj.operId);
		cel.setRemark(coObj.remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(ac.getCardNo());
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setExpired(ac.getExpired());
		cel.setNewExpired(null);
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(occurTime);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_CHANGE_OWNER);
		cel.setCardHolder(pcObj.getName());
		cel.setCardHolderIdType(pcObj.getIdTypeId());
		cel.setCardHolderIdNo(pcObj.getIdNo());
		cardEventLogDaoImpl.insert(cel);
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Edit, "登记或改变实名制信息", "CardNo: "
						+ ac.getCardNo());

		return coObj;
	}

	/**
	 * 卡临时挂失
	 * 
	 * @param cardNo
	 * @param clObj
	 */
	@Override
	public CardLossObject cardTemporaryLoss(PCPSWebInput webInput,
			CardLossObject clObj) throws PCPSApplicationException {
		// 1. 参数检查
		if (clObj == null || PCPSUtil.isEmpty(clObj.cardNo)
				|| clObj.operId == null || clObj.branchNo == null)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		// 2. 如果是执行业务操作,检查备注是否为空
		if (!clObj.isTrail && PCPSUtil.isEmpty(clObj.remark)) {
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		}
		// 3. 检查卡相关属性
		ActivateCard ac = chkCardAttribute(clObj.cardNo, null, null);
		// 检查是否能交易
		isCardCanDoTrans(ac);
		// 检查销售机构日终状态
		checkSaleBranchDayOff(webInput.getOperBranchNo());
		// 判断卡是否有实名信息
		if (ac.getOwnerId() == null) {
			errException("此卡为非实名卡,不能挂失!");
		}
		PersonalCustom pcObj = personalCustomDao
				.getPersonalCustomByPersonalId(ac.getOwnerId());
		if (pcObj == null) {
			errException("该卡的实名制信息未获取到!");
		}
		// 判断卡状态
		if (ac.getLossStatus() != null
				&& (ac.getLossStatus().equals(
						ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED) || ac
						.getLossStatus()
						.equals(
								ActivateCard.ACTIVATECARD_LOSSSTATUS_TEMP_LOSSED))) {
			errException("操作失败,此卡" + clObj.cardNo + " 已挂失!");
		}
		if (!ac.getCloseStatus().equals(
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL)) {
			errException("操作失败,此卡" + clObj.cardNo + " 已销卡!");
		}
		if (ac.getManualLockStatus().equals(
				ActivateCard.ACTIVATECARD_MANUALLOCKSTATUS_LOCKED)) {
			errException("操作失败,此卡" + clObj.cardNo + " 处于锁定状态!");
		}

		// 取当前时间
		Date occurTime = pcpsCommonDaoImpl.getDatabaseSysTime();
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(clObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo())) {
			errException("操作员无效!");
		}
		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(PCPSUtil
						.getICNoByBranchNo(sysOpUser.getOperBranchNo()));
		// 计算费用
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_temporaryLoss, ac.getCardNo(),
				null, issueCompany.getTranDate(), ac.getBalance());

		BigInteger fee = ifp.getFee();
		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_temporaryLoss);

		// 设置返回余额
		clObj.balance = ac.getBalance();
		clObj.fee = fee;

		// 如果是试算,把试算结果返回
		if (clObj.isTrail) {
			return clObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !clObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}
		// 检查收费模式
		if (!PCPSUtil.compareObject(clObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(clObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");
		// 检查优惠的手续费
		if ((clObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(clObj.discountFee) > 0
				|| clObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (clObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(clObj.authOperId, clObj.authPwd, clObj.operId,
					sysOpUser.getOperBranchNo());
		else
			clObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(clObj.discountFee);
		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(clObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			clObj.cashFee = BigInteger.ZERO;
			clObj.cardFee = factfee;
		} else {
			clObj.cashFee = factfee;
			clObj.cardFee = BigInteger.ZERO;
		}
		ac.setLastLossTime(occurTime);
		ac.setLossStatus(ActivateCard.ACTIVATECARD_LOSSSTATUS_TEMP_LOSSED);
		activateCardDaoImpl.update(ac);

		// 卡事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		String accSeqNo = null;

		// 如果需要延期,则执行扣费动作
		if (clObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = clObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = clObj.cardNo;
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = clObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "卡临时挂失手续费");
			// 保留流水号
			accSeqNo = paidResult.accseqno;
			// 设置返回余额
			clObj.balance = paidResult.cardbalance.get(clObj.cardNo);
		}

		// 现金收入记帐
		if (clObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					clObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid, clObj.operId,
					occurTime, "卡临时挂失手续费");

		// 业务单号
		String cardEventOrderSeq = pcpsCommonDaoImpl.getOrderNumber(occurTime,
				clObj.branchNo);
		clObj.orderSeqNo = evid.toString();// 返回的CardEventId

		// 4.记载卡挂失登记日志
		CardLoss cl = new CardLoss();
		cl.setCardLossId(pcpsCommonDaoImpl.getUniqueIntegerKey());
		cl.setCardLossOrderSeq(cardEventOrderSeq);
		cl.setCardNo(clObj.cardNo);
		cl.setRemark(clObj.remark);
		cl.setMasterAccNo(ac.getMasterAccNo());
		cl.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cl.setBranchNo(sysOpUser.getOperBranchNo());
		cl.setCardHolder(pcObj.getName());
		cl.setCardHolderIdNo(pcObj.getIdNo());
		cl.setCardHolderIdType(pcObj.getIdTypeId());
		cl.setTranType(CardLoss.CARDLOSS_TRANTYPE_TEMPORARY);
		cl.setBalance(ac.getBalance());
		cl.setOperId(clObj.operId);
		cl.setTranTime(occurTime);
		cl.setTranDate(issueCompany.getTranDate());
		// 前台输入参数
		cl.setLossName(clObj.ownerName);
		cl.setLossIdType(clObj.ownerIdType);
		cl.setLossIdNo(clObj.ownerIdNo);
		cl.setLossIdImageId(clObj.ownerIdImgId);
		cl.setProxyIdImageId(clObj.proxyIdImgId);
		cl.setProxyIdNo(clObj.proxyIdNo);
		cl.setProxyIdType(clObj.proxyIdType);
		cl.setProxyName(clObj.proxyName);
		// 插入挂失信息
		cardLossDao.insert(cl);

		// 5.记载卡事件日志
		CardEventLog cel = new CardEventLog();
		cel.setBalance(clObj.balance);
		cel.setFee(fee);
		cel.setCardFee(clObj.cardFee);
		cel.setCashFee(clObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(clObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(clObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(clObj.operId);
		cel.setRemark(clObj.remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(ac.getCardNo());
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setExpired(ac.getExpired());
		cel.setNewExpired(null);
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(occurTime);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_CARD_TEMP_LOSS);
		cel.setCardHolder(pcObj.getName());
		cel.setCardHolderIdType(pcObj.getIdTypeId());
		cel.setCardHolderIdNo(pcObj.getIdNo());
		cardEventLogDaoImpl.insert(cel);
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Add, "卡临时挂失", "CardNo: " + ac.getCardNo());

		return clObj;
	}

	/**
	 * 卡解挂失
	 * 
	 * @param cardNo
	 * @param clObj
	 */
	@Override
	public CardLossObject cardRelieveLoss(PCPSWebInput webInput,
			CardLossObject clObj) throws PCPSApplicationException {
		// 1. 参数检查
		if (clObj == null || PCPSUtil.isEmpty(clObj.cardNo)
				|| clObj.operId == null || clObj.branchNo == null)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		// 2. 如果是执行业务操作,检查备注是否为空
		if (!clObj.isTrail && PCPSUtil.isEmpty(clObj.remark)) {
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		}
		// 3. 检查卡相关属性
		ActivateCard ac = chkCardAttribute(clObj.cardNo, null, null);
		// 检查销售机构日终状态
		checkSaleBranchDayOff(webInput.getOperBranchNo());
		// 判断卡是否有实名信息
		if (ac.getOwnerId() == null) {
			errException("此卡为非实名卡,不能解挂失!");
		}
		PersonalCustom pcObj = personalCustomDao
				.getPersonalCustomByPersonalId(ac.getOwnerId());
		if (pcObj == null) {
			errException("该卡的实名制信息未获取到!");
		}
		// 判断卡状态
		if (ac.getLossStatus() != null
				&& ac.getLossStatus().equals(
						ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED_FREE)) {
			errException("操作失败,此卡" + clObj.cardNo + " 已解除挂失!");
		}
		if (!ac.getCloseStatus().equals(
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL)) {
			errException("操作失败,此卡" + clObj.cardNo + " 已销卡!");
		}
		if (ac.getManualLockStatus().equals(
				ActivateCard.ACTIVATECARD_MANUALLOCKSTATUS_LOCKED)) {
			errException("操作失败,此卡" + clObj.cardNo + " 处于锁定状态!");
		}

		// 取当前时间
		Date occurTime = pcpsCommonDaoImpl.getDatabaseSysTime();
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(clObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo())) {
			errException("操作员无效!");
		}
		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(PCPSUtil
						.getICNoByBranchNo(sysOpUser.getOperBranchNo()));
		// 计算费用
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_relieveLoss, ac.getCardNo(),
				null, issueCompany.getTranDate(), ac.getBalance());

		BigInteger fee = ifp.getFee();
		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_relieveLoss);

		// 设置返回余额
		clObj.balance = ac.getBalance();
		clObj.fee = fee;

		// 如果是试算,把试算结果返回
		if (clObj.isTrail) {
			return clObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !clObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}
		// 检查收费模式
		if (!PCPSUtil.compareObject(clObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(clObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");
		// 检查优惠的手续费
		if ((clObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(clObj.discountFee) > 0
				|| clObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (clObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(clObj.authOperId, clObj.authPwd, clObj.operId,
					sysOpUser.getOperBranchNo());
		else
			clObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(clObj.discountFee);
		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(clObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			clObj.cashFee = BigInteger.ZERO;
			clObj.cardFee = factfee;
		} else {
			clObj.cashFee = factfee;
			clObj.cardFee = BigInteger.ZERO;
		}
		ac.setLastLossTime(occurTime);
		ac.setLossStatus(ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED_FREE);
		activateCardDaoImpl.update(ac);

		// 卡事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		String accSeqNo = null;

		// 如果需要延期,则执行扣费动作
		if (clObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = clObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = clObj.cardNo;
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = clObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "卡解除挂失手续费");
			// 保留流水号
			accSeqNo = paidResult.accseqno;
			// 设置返回余额
			clObj.balance = paidResult.cardbalance.get(clObj.cardNo);
		}

		// 现金收入记帐
		if (clObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					clObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid, clObj.operId,
					occurTime, "卡解除挂失手续费");

		// 业务单号
		String cardEventOrderSeq = pcpsCommonDaoImpl.getOrderNumber(occurTime,
				clObj.branchNo);
		clObj.orderSeqNo = evid.toString();// 返回的CardEventId

		// 4.记载卡挂失登记日志
		CardLoss cl = new CardLoss();
		cl.setCardLossId(pcpsCommonDaoImpl.getUniqueIntegerKey());
		cl.setCardLossOrderSeq(cardEventOrderSeq);
		cl.setCardNo(clObj.cardNo);
		cl.setRemark(clObj.remark);
		cl.setMasterAccNo(ac.getMasterAccNo());
		cl.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cl.setBranchNo(sysOpUser.getOperBranchNo());
		cl.setCardHolder(pcObj.getName());
		cl.setCardHolderIdNo(pcObj.getIdNo());
		cl.setCardHolderIdType(pcObj.getIdTypeId());
		cl.setTranType(CardLoss.CARDLOSS_TRANTYPE_RELIEVE);
		cl.setBalance(ac.getBalance());
		cl.setOperId(clObj.operId);
		cl.setTranTime(occurTime);
		cl.setTranDate(issueCompany.getTranDate());
		// 前台输入参数
		cl.setLossName(clObj.ownerName);
		cl.setLossIdType(clObj.ownerIdType);
		cl.setLossIdNo(clObj.ownerIdNo);
		cl.setLossIdImageId(clObj.ownerIdImgId);
		cl.setProxyIdImageId(clObj.proxyIdImgId);
		cl.setProxyIdNo(clObj.proxyIdNo);
		cl.setProxyIdType(clObj.proxyIdType);
		cl.setProxyName(clObj.proxyName);
		// 插入挂失信息
		cardLossDao.insert(cl);

		// 5.记载卡事件日志
		CardEventLog cel = new CardEventLog();
		cel.setBalance(clObj.balance);
		cel.setFee(fee);
		cel.setCardFee(clObj.cardFee);
		cel.setCashFee(clObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(clObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(clObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(clObj.operId);
		cel.setRemark(clObj.remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(ac.getCardNo());
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setExpired(ac.getExpired());
		cel.setNewExpired(null);
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(occurTime);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_CARD_UN_LOSS);
		cel.setCardHolder(pcObj.getName());
		cel.setCardHolderIdType(pcObj.getIdTypeId());
		cel.setCardHolderIdNo(pcObj.getIdNo());
		cardEventLogDaoImpl.insert(cel);
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Add, "卡解除挂失", "CardNo: " + ac.getCardNo());

		return clObj;
	}

	/**
	 * 卡正式挂失
	 * 
	 * @param cardNo
	 * @param clObj
	 */
	@Override
	public CardLossObject cardOfficialLoss(PCPSWebInput webInput,
			CardLossObject clObj) throws PCPSApplicationException {
		// 1. 参数检查
		if (clObj == null || PCPSUtil.isEmpty(clObj.cardNo)
				|| clObj.operId == null || clObj.branchNo == null)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		// 2. 如果是执行业务操作,检查备注是否为空
		if (!clObj.isTrail && PCPSUtil.isEmpty(clObj.remark)) {
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		}
		// 3. 检查卡相关属性
		ActivateCard ac = chkCardAttribute(clObj.cardNo, null, null);
		// 检查是否能交易
		isCardCanDoTrans(ac);
		// 检查销售机构日终状态
		checkSaleBranchDayOff(webInput.getOperBranchNo());
		// 判断卡是否有实名信息
		if (ac.getOwnerId() == null) {
			errException("此卡为非实名卡,不能挂失!");
		}
		PersonalCustom pcObj = personalCustomDao
				.getPersonalCustomByPersonalId(ac.getOwnerId());
		if (pcObj == null) {
			errException("该卡的实名制信息未获取到!");
		}
		// 判断卡状态
		if (ac.getLossStatus() != null
				&& ac.getLossStatus().equals(
						ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED)) {
			errException("操作失败,此卡" + clObj.cardNo + " 已挂失!");
		}
		if (!ac.getCloseStatus().equals(
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL)) {
			errException("操作失败,此卡" + clObj.cardNo + " 已销卡!");
		}
		if (ac.getManualLockStatus().equals(
				ActivateCard.ACTIVATECARD_MANUALLOCKSTATUS_LOCKED)) {
			errException("操作失败,此卡" + clObj.cardNo + " 处于锁定状态!");
		}

		// 取当前时间
		Date occurTime = pcpsCommonDaoImpl.getDatabaseSysTime();
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(clObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo())) {
			errException("操作员无效!");
		}
		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(PCPSUtil
						.getICNoByBranchNo(sysOpUser.getOperBranchNo()));
		// 计算费用
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_loss, ac.getCardNo(), null,
				issueCompany.getTranDate(), ac.getBalance());

		BigInteger fee = ifp.getFee();
		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_loss);

		// 设置返回余额
		clObj.balance = ac.getBalance();
		clObj.fee = fee;

		// 如果是试算,把试算结果返回
		if (clObj.isTrail) {
			return clObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !clObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}

		// 检查收费模式
		if (!PCPSUtil.compareObject(clObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(clObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");
		// 检查优惠的手续费
		if ((clObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(clObj.discountFee) > 0
				|| clObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (clObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(clObj.authOperId, clObj.authPwd, clObj.operId,
					sysOpUser.getOperBranchNo());
		else
			clObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(clObj.discountFee);

		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(clObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			clObj.cashFee = BigInteger.ZERO;
			clObj.cardFee = factfee;
		} else {
			clObj.cashFee = factfee;
			clObj.cardFee = BigInteger.ZERO;
		}
		if (!ac.getLossStatus().equals(
				ActivateCard.ACTIVATECARD_LOSSSTATUS_TEMP_LOSSED)) {
			ac.setLastLossTime(occurTime);
		}
		ac.setLossStatus(ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED);
		activateCardDaoImpl.update(ac);

		// 卡事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		String accSeqNo = null;

		// 如果需要延期,则执行扣费动作
		if (clObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = clObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = clObj.cardNo;
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = clObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "卡正式挂失手续费");
			// 保留流水号
			accSeqNo = paidResult.accseqno;
			// 设置返回余额
			clObj.balance = paidResult.cardbalance.get(clObj.cardNo);
		}

		// 现金收入记帐
		if (clObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					clObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid, clObj.operId,
					occurTime, "卡正式挂失手续费");

		// 业务单号
		String cardEventOrderSeq = pcpsCommonDaoImpl.getOrderNumber(occurTime,
				clObj.branchNo);
		clObj.orderSeqNo = evid.toString();// 返回的CardEventId

		// 4.记载卡挂失登记日志
		CardLoss cl = new CardLoss();
		cl.setCardLossId(pcpsCommonDaoImpl.getUniqueIntegerKey());
		cl.setCardLossOrderSeq(cardEventOrderSeq);
		cl.setCardNo(clObj.cardNo);
		cl.setRemark(clObj.remark);
		cl.setMasterAccNo(ac.getMasterAccNo());
		cl.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cl.setBranchNo(sysOpUser.getOperBranchNo());
		cl.setCardHolder(pcObj.getName());
		cl.setCardHolderIdNo(pcObj.getIdNo());
		cl.setCardHolderIdType(pcObj.getIdTypeId());
		cl.setTranType(CardLoss.CARDLOSS_TRANTYPE_OFFICIAL);
		cl.setBalance(ac.getBalance());
		cl.setOperId(clObj.operId);
		cl.setTranTime(occurTime);
		cl.setTranDate(issueCompany.getTranDate());
		// 前台输入参数
		cl.setLossName(clObj.ownerName);
		cl.setLossIdType(clObj.ownerIdType);
		cl.setLossIdNo(clObj.ownerIdNo);
		cl.setLossIdImageId(clObj.ownerIdImgId);
		cl.setProxyIdImageId(clObj.proxyIdImgId);
		cl.setProxyIdNo(clObj.proxyIdNo);
		cl.setProxyIdType(clObj.proxyIdType);
		cl.setProxyName(clObj.proxyName);
		// 插入挂失信息
		cardLossDao.insert(cl);

		// 5.记载卡事件日志
		CardEventLog cel = new CardEventLog();
		cel.setBalance(clObj.balance);
		cel.setFee(fee);
		cel.setCardFee(clObj.cardFee);
		cel.setCashFee(clObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(clObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(clObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(clObj.operId);
		cel.setRemark(clObj.remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(ac.getCardNo());
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setExpired(ac.getExpired());
		cel.setNewExpired(null);
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(occurTime);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_CARD_LOSS);
		cel.setCardHolder(pcObj.getName());
		cel.setCardHolderIdType(pcObj.getIdTypeId());
		cel.setCardHolderIdNo(pcObj.getIdNo());
		cardEventLogDaoImpl.insert(cel);
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Add, "卡正式挂失", "CardNo: " + ac.getCardNo());

		return clObj;
	}

	/**
	 * 检查卡属性
	 */
	private ActivateCard chkCardAttribute(String CardNo, String Pwd,
			BigInteger Amount) throws PCPSApplicationException {
		if (PCPSUtil.isEmpty(CardNo))
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_SYS,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);

		PCPSUtil.Log("chkCardAttribute:" + CardNo);

		// 检索卡信息
		ActivateCard ac = getValidateActivateCardByCardNo(CardNo);

		// 取数据库服务器时间
		java.util.Date curSysDate = pcpsCommonDaoImpl.getDatabaseSysTime();

		// 检索制卡控制批次
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(ac.getBatchNo());
		// 取卡系统全局数据字典
		IssueCompany issuecmp = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(mcc.getIssueCompanyNo());

		// 比较是否到期
		if (ac.getExpired() != null
				&& curSysDate.compareTo(ac.getExpired()) > 0)
			throw new CardTranApplicationException(TuxedoRespCode.RC_EXPIRED,
					"卡已经过期!");

		// 检查卡是否被锁定
		if (PCPSUtil.isCardLocked(curSysDate, ac.getPwdErrCnt(), ac
				.getLastPwdErrTime(), issuecmp.getMaxPwdErrCnt(), issuecmp
				.getMaxPwdErrCnt()))
			throw new CardTranApplicationException(TuxedoRespCode.RC_LOCKED,
					"密码锁定!");

		// 检查手工锁定状态
		if (PCPSUtil.compareObject(ac.getManualLockStatus(),
				ActivateCard.ACTIVATECARD_MANUALLOCKSTATUS_LOCKED))
			throw new CardTranApplicationException(TuxedoRespCode.RC_LOCKED,
					"已锁定!");

		// 检查发生额 -- 准备扣款
		if (Amount != null) {
			if (ac.getBalance().subtract(Amount).compareTo(BigInteger.ZERO) < 0)
				throw new CardTranApplicationException(TuxedoRespCode.RC_LACK,
						"余额不足!");
		}

		// 如果无需检查密码
		if (PCPSUtil.isEmpty(Pwd))
			return ac;

		// 检查密码,通过返回
		if (ac.VerifyPassword(Pwd)) {
			// 如果需要解锁,则解锁该卡
			if (ac.getPwdErrCnt() != 0)
				activateCardDaoImpl.resetPwdErrCnt(CardNo);
			return ac;
		}

		// 增加密码错误次数
		activateCardDaoImpl.incPwdErrCnt(CardNo);
		ac = getValidateActivateCardByCardNo(CardNo);

		// 再次检查是否锁定
		if (PCPSUtil.isCardLocked(curSysDate, ac.getPwdErrCnt(), ac
				.getLastPwdErrTime(), issuecmp.getMaxPwdErrCnt(), issuecmp
				.getPwdErrLimit())) {
			// 如果锁定单独记载卡密码错锁定日志
			createCardEventLog(CardNo, curSysDate,
					CardEventLog.CARDEVENTLOG_EVENTTYPE_PWDERRLOCK, null, "");
		}

		throw new CardTranApplicationException(TuxedoRespCode.RC_PWDERR, "密码错!");
	}

	/**
	 * 检查该卡是否能交易
	 * 
	 * @param ac
	 * @throws PCPSApplicationException
	 */
	public void isCardCanDoTrans(ActivateCard ac)
			throws PCPSApplicationException {
		// 判断销卡状态 -- 不等于未销卡
		if (PCPSUtil.compareObject(ac.getCloseStatus(),
				ActivateCard.ACTIVATECARD_CLOSESTATUS_CLOSED))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡已赎回!");
		if (PCPSUtil.compareObject(ac.getCloseStatus(),
				ActivateCard.ACTIVATECARD_CLOSESTATUS_CLOSED_ISSUE_NEW))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡已补发新卡!");

		// 判断挂失状态 -- 等于正式挂失或者临时挂失
		if (PCPSUtil.compareObject(ac.getLossStatus(),
				ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED))
			throw new CardTranApplicationException(TuxedoRespCode.RC_LOSSED,
					"已挂失的卡!");

		if (ac.getSaleOrderId() == null)
			return;

		// 判断销售单是否被冻结
		SaleOrder saleOrder = saleOrderDaoImpl.getSaleOrderBySaleOrderId(ac
				.getSaleOrderId());
		if (saleOrder == null)
			return;

		String orderStatus = saleOrder.getOrderStatus();

		// 受限制的卡 -- 销售单已冻结,则此卡不能消费
		if (!(PCPSUtil.compareObject(orderStatus,
				SaleOrder.SALEORDER_ORDERSTATUS_ACTIVATED) || PCPSUtil
				.compareObject(orderStatus,
						SaleOrder.SALEORDER_ORDERSTATUS_UNDOFREEZE)))
			throw new CardTranApplicationException(TuxedoRespCode.RC_LIMIT,
					"销售单已冻结");
	}

	/**
	 * 查询有效的激活卡
	 */
	public ActivateCard getValidActivateCard(String CardNo, String Pwd,
			BigInteger Amount) throws PCPSApplicationException {
		// 获取并检查卡的有效性
		ActivateCard ac = chkCardAttribute(CardNo, Pwd, Amount);

		// 检查是否能交易
		isCardCanDoTrans(ac);

		return ac;
	}

	/**
	 * 获取所有待记帐的卡列表MAP
	 * 
	 * @return
	 * @throws PCPSApplicationException
	 */
	private Map<String, ActivateCard> getAllPaidCardMap(PaidParam paidParam)
			throws PCPSApplicationException {
		Map<String, ActivateCard> allcard = new HashMap<String, ActivateCard>();

		// 以非锁定方式检查
		for (PaidParam.PaidCardParam pcp : paidParam.allPaidCardList) {
			// 检查卡号
			if (PCPSUtil.isEmpty(pcp.cardNo) || allcard.containsKey(pcp.cardNo))
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_INVALID);

			// 检查密码
			/*
			 * if (PCPSUtil.isEmpty(pcp.pwd)) throw new
			 * CardTranApplicationException(TuxedoRespCode.RC_PWDERR);
			 */

			// 检查支付金额
			if (pcp.amt == null || pcp.amt.compareTo(BigInteger.ZERO) <= 0)
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_AMOUNT, "发生额非法");

			// 检查手续费
			if (pcp.fee == null)
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_AMOUNT, "手续费非法");

			// 取卡属性、验证密码、余额是否足够等
			ActivateCard ac = chkCardAttribute(pcp.cardNo, pcp.pwd, pcp.amt);

			// 判断卡状态
			isCardCanDoTrans(ac);
		}

		// 以锁定方式重新检索一次
		for (PaidParam.PaidCardParam pcp : paidParam.allPaidCardList) {
			ActivateCard ac = activateCardDaoImpl
					.getActivateCardByCardNoForUpdate(pcp.cardNo);
			allcard.put(ac.getCardNo(), ac);
		}

		// 必须至少存在1条记录
		if (allcard.size() < 1)
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"必须存在至少1张卡");

		return allcard;
	}

	/**
	 * 商户是否属于商圈
	 * 
	 * @param merchantNo
	 * @param businessDistrictId
	 * @return
	 * @throws PCPSApplicationException
	 */
	private boolean merchantBelongBusinessDistrict(String merchantNo,
			BigInteger businessDistrictId) throws PCPSApplicationException {
		BusinessDistrictMerchant bdm = new BusinessDistrictMerchant();
		bdm.setMerchantNo(merchantNo);
		bdm.setBusinessDistrictId(businessDistrictId);
		return businessDistrictMerchantDaoImpl
				.getBusinessDistrictMerchantByPrimaryKey(bdm) == null ? false
				: true;
	}

	/**
	 * 检查指定的卡能否在指定的商户处消费
	 * 
	 * @param ac
	 * @param mrch
	 * @throws PCPSApplicationException
	 */
	private void canPaidOnMerchant(ActivateCard ac, Merchant mrch)
			throws PCPSApplicationException {
		boolean hasbind = false;

		// 一、先检查卡种类与商户的直接绑定关系
		List<CardClassicBindMerchant> ccbmlist = cardClassicBindMerchantDaoImpl
				.getAllBindMerchantByCardClassicId(ac.getCardClassicId());
		if (ccbmlist != null && ccbmlist.size() >= 1) {
			hasbind = true;
			// 本卡种类绑定了商户
			for (CardClassicBindMerchant ccbm : ccbmlist) {
				// 如果找到了则返回
				if (PCPSUtil.compareObject(ccbm.getMerchantNo(), mrch
						.getMerchantNo()))
					return;
			}
		}

		// 二、其次检查卡种类是否绑定了商圈
		// 1. 如绑定了商圈,则若商户亦绑定了该商圈或下级子商圈,则允许交易,否则不允许交易
		// 2. 如未绑定商圈,则视一的情况决定是否允许交易

		// 卡种类绑定的商圈及子商圈列表
		List<CardClassicBindDistrict> ccbdlist = cardClassicBindDistrictDaoImpl
				.getCardClassicBindDistrictListByCardClassicId(ac
						.getCardClassicId());
		if (ccbdlist != null && ccbdlist.size() >= 1) {
			hasbind = true;
			Map<BigInteger, BigInteger> bdmap = new HashMap<BigInteger, BigInteger>();

			// 将卡种类绑定的商圈加入到map中
			for (CardClassicBindDistrict ccbd : ccbdlist) {
				if (!bdmap.containsKey(ccbd.getBusinessDistrictId())) {
					// 判断是否存在该商圈ID与本商户的绑定关系
					if (merchantBelongBusinessDistrict(mrch.getMerchantNo(),
							ccbd.getBusinessDistrictId()))
						return;
					bdmap.put(ccbd.getBusinessDistrictId(), ccbd
							.getBusinessDistrictId());
					// 取所有的商圈以及子商圈
					List<BusinessDistrict> curbdlist = businessDistrictDaoImpl
							.getSelfAllChildBusinessDistrictByBusinessDistrictId(ccbd
									.getBusinessDistrictId());
					for (BusinessDistrict bd : curbdlist) {
						if (!bdmap.containsKey(ccbd.getBusinessDistrictId())) {
							bdmap.put(bd.getBusinessDistrictId(), bd
									.getBusinessDistrictId());
							// 判断是否存在该商圈ID与本商户的绑定关系
							if (merchantBelongBusinessDistrict(mrch
									.getMerchantNo(), ccbd
									.getBusinessDistrictId()))
								return;
						}
					}
				}
			}
		}

		if (hasbind) {
			throw new CardTranApplicationException(TuxedoRespCode.RC_LIMIT,
					"卡号" + ac.getCardNo() + "在本商户处被限制交易!");
		}
	}

	/**
	 * 检查兼容性,返回有效的发卡商NO
	 * 
	 * @param mrch
	 */
	private String getValidIssueCompanyNo(Merchant mrch,
			Map<String, ActivateCard> allcard) throws PCPSApplicationException {

		Map<BigInteger, String> cardclassic = new HashMap<BigInteger, String>();
		String issueCompanyNo = null;

		// 检查所有的卡归属于那些卡种类
		for (Map.Entry<String, ActivateCard> entry : allcard.entrySet()) {
			String cardNo = entry.getKey();
			BigInteger ccid = entry.getValue().getCardClassicId();
			if (!cardclassic.containsKey(ccid)) {
				cardclassic.put(ccid, cardNo);
				CardClassic cc = cardClassicDaoImpl
						.getCardClassicByCardClassicId(ccid);
				if (cc == null)
					throw new CardTranApplicationException(
							TuxedoRespCode.RC_INVALID, "卡号" + cardNo + "卡种类无效!");
				if (issueCompanyNo == null)
					issueCompanyNo = cc.getIssueCompanyNo();

				if (!PCPSUtil.compareObject(issueCompanyNo, cc
						.getIssueCompanyNo()))
					throw new CardTranApplicationException(
							TuxedoRespCode.RC_ISSUE, "卡号" + cardNo + "非发卡商所有!");

				// 检查指定的卡能否在商户处消费
				canPaidOnMerchant(entry.getValue(), mrch);
			}
		}

		if (PCPSUtil.isEmpty(issueCompanyNo))
			throw new CardTranApplicationException(TuxedoRespCode.RC_ISSUE,
					"发卡商为空!");

		return issueCompanyNo;
	}

	/**
	 * 抛出无此卡号的异常
	 * 
	 * @param cardNo
	 * @throws PCPSApplicationException
	 */
	private void noSuchCard(String cardNo) throws PCPSApplicationException {
		throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
				"无此卡号" + cardNo);
	}

	/**
	 * 检查某记帐参数的合法性
	 * 
	 * @param cap
	 * @throws PCPSApplicationException
	 */
	private void checkOneCardAccountParam(CardAccountParam cap)
			throws PCPSApplicationException {
		// 检查卡号
		if (PCPSUtil.isEmpty(cap.cardNo))
			noSuchCard(cap.cardNo);

		// 消费发生金额(>=0)
		if (cap.paidAmount == null
				|| BigInteger.ZERO.compareTo(cap.paidAmount) > 0)
			throw new CardTranApplicationException(TuxedoRespCode.RC_AMOUNT,
					"无效支付金额"
							+ (cap.paidAmount == null ? "null" : cap.paidAmount
									.toString()));

		// 手续费发生(可正可负可为0)
		if (cap.feeAmount == null)
			throw new CardTranApplicationException(TuxedoRespCode.RC_AMOUNT,
					"无效手续费金额!");
	}

	/**
	 * 产生一笔或多笔记帐明细
	 * 
	 * @param cardNo
	 * @param isubmap
	 * @param cadlist
	 * @param amt
	 * @param isfee
	 * 
	 * @throws PCPSApplicationException
	 */
	private void generateAccountDetail(String cardNo,
			Map<BigInteger, SubAccount> isubmap,
			List<CardAccountDetail> cadlist, BigInteger amt, boolean isfee)
			throws PCPSApplicationException {
		CardAccountDetail cad = null;
		SubAccount sa = null;

		// 无发生金额
		if (amt.compareTo(BigInteger.ZERO) == 0)
			return;

		// 发生额为负值,可以肯定为优惠的手续费
		if (amt.compareTo(BigInteger.ZERO) < 0) {
			// 始终取第1个子帐户
			for (Map.Entry<BigInteger, SubAccount> saentry : isubmap.entrySet()) {
				sa = saentry.getValue();

				sa.setBalance(sa.getBalance().subtract(amt));

				cad = new CardAccountDetail();

				cad.CardNo = cardNo;
				cad.MasterAccNo = sa.getMasterAccNo();
				cad.SubAccNo = sa.getSubAccNo();
				cad.OpenBranchNo = sa.getOpenBranchNo();
				cad.SalesGroupId = sa.getSalesGroupId();
				cad.paidAmount = BigInteger.ZERO;
				cad.feeAmount = amt;

				cadlist.add(cad);
				return;
			}
		}

		// 始终取第1个有余额的子帐户
		for (Map.Entry<BigInteger, SubAccount> saentry : isubmap.entrySet()) {
			sa = saentry.getValue();
			if (sa.getBalance().compareTo(BigInteger.ZERO) == 0)
				continue;
			BigInteger curamt = null;
			if (sa.getBalance().compareTo(amt) >= 0)
				curamt = amt;
			else
				curamt = sa.getBalance();
			cad = new CardAccountDetail();

			cad.CardNo = cardNo;
			cad.MasterAccNo = sa.getMasterAccNo();
			cad.SubAccNo = sa.getSubAccNo();
			cad.OpenBranchNo = sa.getOpenBranchNo();
			cad.SalesGroupId = sa.getSalesGroupId();
			cad.paidAmount = BigInteger.ZERO;
			cad.feeAmount = BigInteger.ZERO;

			if (isfee)
				cad.feeAmount = curamt;
			else
				cad.paidAmount = curamt;

			sa.setBalance(sa.getBalance().subtract(curamt));
			amt = amt.subtract(curamt);
			cadlist.add(cad);

			if (amt.compareTo(BigInteger.ZERO) == 0)
				break;
		}

		if (amt.compareTo(BigInteger.ZERO) != 0)
			throw new CardTranApplicationException(TuxedoRespCode.RC_LACK,
					"分配记帐金额失败!");
	}

	/**
	 * 根据卡记帐参数返回分配好的帐户子系统记帐明细
	 * 
	 * @param caplist
	 * @return
	 * @throws PCPSApplicationException
	 */
	private List<CardAccountDetail> getCardAccountDetail(
			List<CardAccountParam> caplist) throws PCPSApplicationException {

		List<CardAccountDetail> cadlist = new ArrayList<CardAccountDetail>();

		// 卡号与有效余额的映射MAP
		Map<String, BigInteger> masmap = new HashMap<String, BigInteger>();

		// 卡号与子帐号map
		Map<String, Map<BigInteger, SubAccount>> submap = new HashMap<String, Map<BigInteger, SubAccount>>();

		ActivateCard ac = null;

		// 1. 检索主、子帐号余额map
		for (CardAccountParam cap : caplist) {
			// 检查记帐参数
			checkOneCardAccountParam(cap);
			ac = activateCardDaoImpl.getActivateCardByCardNo(cap.cardNo);
			if (ac == null || ac.getMasterAccNo() == null)
				noSuchCard(cap.cardNo);
			if (masmap.containsKey(cap.cardNo))
				continue;
			MasterAccount mas = masterAccountDaoImpl
					.getMasterAccountByMasterAccNoForUpdate(ac.getMasterAccNo());
			if (mas == null)
				noSuchCard(cap.cardNo);
			// 检查余额的一致性
			if (!PCPSUtil.compareObject(mas.getBalance(), ac.getBalance()))
				throw new CardTranApplicationException(TuxedoRespCode.RC_LACK,
						"卡" + cap.cardNo + "余额与主帐户" + mas.getMasterAccNo()
								+ "余额不一致");
			// 有效余额为总余额 - 已冻结金额 - 待审核充值金额 - 待审核赎回资金
			// System.out.println("总余额="+mas.getBalance());
			// System.out.println("已冻结金额="+mas.getFreezeAmount());
			// System.out.println("待审核充值金额="+mas.getAuthDeposit());
			// System.out.println("待审核赎回资金="+mas.getAuthRedemp());
			// BigInteger validBalance = mas.getBalance().subtract(
			// mas.getFreezeAmount()).subtract(mas.getAuthDeposit())
			// .subtract(mas.getAuthRedemp());
			BigInteger validBalance = mas.getBalance().subtract(
					mas.getFreezeAmount()).subtract(mas.getAuthRedemp());
			if (validBalance.compareTo(BigInteger.ZERO) < 0)
				throw new CardTranApplicationException(TuxedoRespCode.RC_LACK,
						"卡" + cap.cardNo + "有效余额不足");
			masmap.put(ac.getCardNo(), validBalance);

			// 取所有的子帐户
			List<SubAccount> subacclist = subAccountDaoImpl
					.getAllSubAccountForPaidByMasterAccNo(ac.getMasterAccNo());

			Map<BigInteger, SubAccount> isubmap = new HashMap<BigInteger, SubAccount>();
			for (SubAccount sa : subacclist)
				isubmap.put(sa.getSubAccNo(), sa);

			// 加入到submap
			submap.put(cap.cardNo, isubmap);
		}

		// 2. 分配记帐明细
		for (CardAccountParam cap : caplist) {
			// 忽略全0的记帐记录
			if (BigInteger.ZERO.equals(cap.paidAmount)
					&& BigInteger.ZERO.equals(cap.feeAmount))
				continue;

			BigInteger mas_bal = masmap.remove(cap.cardNo);

			if (BigInteger.ZERO.compareTo(cap.paidAmount) < 0) {
				mas_bal = mas_bal.subtract(cap.paidAmount);
				// 产生一条或若干条记帐明细数据
				Map<BigInteger, SubAccount> isubmap = submap.remove(cap.cardNo);
				generateAccountDetail(cap.cardNo, isubmap, cadlist,
						cap.paidAmount, false);
				submap.put(cap.cardNo, isubmap);
			}

			if (BigInteger.ZERO.compareTo(cap.feeAmount) != 0) {
				mas_bal = mas_bal.subtract(cap.feeAmount);
				// 产生一条或若干条记帐明细数据
				Map<BigInteger, SubAccount> isubmap = submap.remove(cap.cardNo);
				generateAccountDetail(cap.cardNo, isubmap, cadlist,
						cap.feeAmount, true);
				submap.put(cap.cardNo, isubmap);
			}

			if (BigInteger.ZERO.compareTo(mas_bal) > 0)
				throw new CardTranApplicationException(TuxedoRespCode.RC_LACK,
						"卡" + cap.cardNo + "余额不足");

			masmap.put(cap.cardNo, mas_bal);
		}

		return cadlist;
	}

	/**
	 * 获取更新后的卡余额
	 * 
	 * @param allcard
	 * @throws PCPSApplicationException
	 */
	private Map<String, BigInteger> getCardBalance(
			Map<String, ActivateCard> allcard) throws PCPSApplicationException {

		Map<String, BigInteger> cardbal = new HashMap<String, BigInteger>();

		for (Map.Entry<String, ActivateCard> entry : allcard.entrySet()) {
			ActivateCard ac = entry.getValue();
			MasterAccount ma = masterAccountDaoImpl
					.getMasterAccountByMasterAccNoForUpdate(ac.getMasterAccNo());
			cardbal.put(entry.getKey(), ma.getBalance());
		}

		return cardbal;
	}

	/**
	 * 批量卡支付接口
	 * 
	 * @param paidParam
	 *            支付参数
	 * @throws PCPSApplicationException
	 */
	public PaidResult Paid(PaidParam paidParam) throws PCPSApplicationException {
		// 检查入口参数
		if (paidParam == null || PCPSUtil.isEmpty(paidParam.merchantNo)
				|| PCPSUtil.isEmpty(paidParam.tranSeqNo)
				|| paidParam.tranDate == null
				|| paidParam.allPaidCardList == null
				|| paidParam.allPaidCardList.size() < 1)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_SYS,
					TuxedoRespCode.RC_NOMERCHANT,
					CardTranApplicationException.ERRMSG_NULLPOINTER);

		// 商户
		Merchant mrch = merchantDaoImpl
				.getMerchantByMerchantNo(paidParam.merchantNo);
		if (mrch == null)
			throw new CardTranApplicationException(TuxedoRespCode.RC_NOMERCHANT);

		// 生成业务摘要
		String summary = mrch.getMerchantName();

		// 获取列表
		Map<String, ActivateCard> allcard = getAllPaidCardMap(paidParam);

		// 检查兼容性(所有卡的卡种类允许在该商户处消费)
		String issueCompanyNo = getValidIssueCompanyNo(mrch, allcard);

		// 目前,商户与卡必须归属同一发卡商,以后可能会不同
		if (!PCPSUtil.compareObject(issueCompanyNo, paidParam.issueCompanyNo))
			throw new CardTranApplicationException(
					TuxedoRespCode.RC_NOMERCHANT, "无此商户");

		ArrayList<AccountParam> accountParamList = new ArrayList<AccountParam>();

		// 生成卡记帐返回列表
		PaidResult paidResult = new PaidResult();
		List<CardAccountParam> caplist = new ArrayList<CardAccountParam>();

		// 生成caplist
		for (PaidParam.PaidCardParam pcp : paidParam.allPaidCardList) {
			CardAccountParam cap = new CardAccountParam();
			cap.cardNo = pcp.cardNo;
			cap.paidAmount = pcp.amt;
			cap.feeAmount = pcp.fee;
			/* yxb 2013.07.04 修正 消费之后余额不减反增 */
			if (BigInteger.ZERO.compareTo(pcp.fee) > 0
					&& pcp.fee.abs().compareTo(pcp.amt) >= 0)
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_AMOUNT, String.format(
								"卡%s发生额%s手续费%s无效", pcp.cardNo, pcp.amt
										.toString(), pcp.fee.toString()));
			caplist.add(cap);
		}

		List<CardAccountDetail> all_cad = getCardAccountDetail(caplist);

		// 把all_cad转换成accountParamList
		for (CardAccountDetail cad : all_cad) {
			AccountParam ap = new AccountParam();
			ap.subAccNo = cad.SubAccNo;
			// 全部为借方记帐
			ap.creditAmount = BigInteger.ZERO;
			ap.debitAmount = cad.paidAmount.add(cad.feeAmount);
			if (cad.paidAmount.compareTo(BigInteger.ZERO) > 0) {
				ap.tranType = AccountSystemAddTradDetail.TRANTYPE_CONSUME;
				ap.summary = "[消费]" + summary;
			} else {
				ap.tranType = AccountSystemAddTradDetail.TRANTYPE_FEE;
				ap.summary = "[手续费]" + summary;
			}
			// 加入到记帐列表
			accountParamList.add(ap);

			// 加入到返回列表
			PaidResult.AccountDetail ad = paidResult.new AccountDetail();

			ad.CardNo = cad.CardNo;
			ad.MasterAccNo = cad.MasterAccNo;
			ad.SubAccNo = cad.SubAccNo;
			ad.OpenBranchNo = cad.OpenBranchNo;
			ad.SalesGroupId = cad.SalesGroupId;
			ad.Amount = cad.paidAmount;
			ad.feeAmount = cad.feeAmount;

			paidResult.acclist.add(ad);
		}

		// 调用核心帐户子系统记帐
		paidResult.accseqno = accountBusinessImpl.Account(issueCompanyNo,
				paidParam.tranDate, pcpsCommonDaoImpl.getDatabaseSysTime(),
				paidParam.tranSeqNo, paidParam.operId, summary,
				accountParamList);

		// 获取更新后卡余额
		paidResult.cardbalance = getCardBalance(allcard);

		// 返回结果
		return paidResult;
	}

	/**
	 * 支付取消
	 * 
	 * @param paidParam
	 *            支付参数
	 * @throws PCPSApplicationException
	 */
	public PaidResult PaidCancel(PaidParam paidParam)
			throws PCPSApplicationException {

		// 取原始记帐记录
		List<AccountSystemAddTradDetail> astdlist = accountSystemAddTradDetailDaoImpl
				.getAllAccountSystemAddTradDetailByAccSeqNo(paidParam.cancelAccSeqNo);

		if (astdlist == null || astdlist.size() < 1)
			throw new CardTranApplicationException(TuxedoRespCode.RC_NONEXIST,
					"原交易未找到!");

		Map<String, ActivateCard> allcard = new HashMap<String, ActivateCard>();

		// 循环
		for (AccountSystemAddTradDetail astd : astdlist) {
			// 此处不用原流水中的卡号的原因是,有可能此间卡号挂失补发了,因此以主帐户当前的卡号为准
			MasterAccount macc = masterAccountDaoImpl
					.getMasterAccountByMasterAccNo(astd.getMasterAccNo());
			if (macc == null)
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_INVALID, "卡号无效!");
			String cardNo = macc.getCardNo();
			// 如果没有卡号则忽略
			if (PCPSUtil.isEmpty(cardNo))
				continue;
			if (allcard.containsKey(cardNo))
				continue;

			ActivateCard ac = getValidateActivateCardByCardNo(cardNo);

			// 判断销卡状态 -- 不等于未销卡
			if (!PCPSUtil.compareObject(ac.getCloseStatus(),
					ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL)) {
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_INVALID, "卡号[NEW:" + cardNo + ",OLD:"
								+ astd.getCardNo() + "]已经销卡");
			}
			allcard.put(cardNo, ac);
		}

		// 生成卡记帐返回列表
		PaidResult paidResult = new PaidResult();

		// 商户
		Merchant mrch = merchantDaoImpl
				.getMerchantByMerchantNo(paidParam.merchantNo);
		if (mrch == null)
			throw new CardTranApplicationException(
					TuxedoRespCode.RC_NOMERCHANT, "无效商户!");

		// 生成业务摘要
		String summary = mrch.getMerchantName() + "消费撤销/退货";

		paidResult.accseqno = accountBusinessImpl.AccountCancel(
				paidParam.issueCompanyNo, paidParam.tranDate, pcpsCommonDaoImpl
						.getDatabaseSysTime(), paidParam.tranSeqNo,
				paidParam.cancelAccSeqNo, paidParam.operId, summary);

		// 获取更新后卡余额
		paidResult.cardbalance = getCardBalance(allcard);

		return paidResult;
	}

	/**
	 * 重做支付
	 * 
	 * @param paidParam
	 *            支付参数
	 * @throws PCPSApplicationException
	 */
	public PaidResult redoPaid(PaidParam paidParam)
			throws PCPSApplicationException {

		// 取原始记帐记录
		List<AccountSystemAddTradDetail> astdlist = accountSystemAddTradDetailDaoImpl
				.getAllAccountSystemAddTradDetailByAccSeqNo(paidParam.redoAccSeqNo);

		if (astdlist == null || astdlist.size() < 1)
			throw new CardTranApplicationException(TuxedoRespCode.RC_NONEXIST,
					"原交易未找到!");

		Map<String, ActivateCard> allcard = new HashMap<String, ActivateCard>();

		// 循环
		for (AccountSystemAddTradDetail astd : astdlist) {
			// 此处不用原流水中的卡号的原因是,有可能此间卡号挂失补发了,因此以主帐户当前的卡号为准
			MasterAccount macc = masterAccountDaoImpl
					.getMasterAccountByMasterAccNo(astd.getMasterAccNo());
			if (macc == null)
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_INVALID, "卡号无效!");
			String cardNo = macc.getCardNo();
			// 如果没有卡号则忽略
			if (PCPSUtil.isEmpty(cardNo))
				continue;
			if (allcard.containsKey(cardNo))
				continue;

			ActivateCard ac = getValidateActivateCardByCardNo(cardNo);

			// 判断销卡状态 -- 不等于未销卡
			if (!PCPSUtil.compareObject(ac.getCloseStatus(),
					ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL)) {
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_INVALID, "卡号[NEW:" + cardNo + ",OLD:"
								+ astd.getCardNo() + "]已经销卡");
			}
			allcard.put(cardNo, ac);
		}

		// 生成卡记帐返回列表
		PaidResult paidResult = new PaidResult();

		// 商户
		Merchant mrch = merchantDaoImpl
				.getMerchantByMerchantNo(paidParam.merchantNo);
		if (mrch == null)
			throw new CardTranApplicationException(
					TuxedoRespCode.RC_NOMERCHANT, "无效商户!");

		// 生成业务摘要
		String summary = mrch.getMerchantName() + "重做消费";

		// 重新记帐
		paidResult.accseqno = accountBusinessImpl.redoAccount(
				paidParam.issueCompanyNo, paidParam.tranDate, pcpsCommonDaoImpl
						.getDatabaseSysTime(), paidParam.tranSeqNo,
				paidParam.redoAccSeqNo, paidParam.operId, summary);

		// 获取更新后卡余额
		paidResult.cardbalance = getCardBalance(allcard);

		return paidResult;
	}

	/**
	 * 扣费模式参数
	 * 
	 * @author yxb
	 * 
	 */
	class FeeType {
		// 固定
		public static final int FEETYPE_FIXED = 0;
		// 固定最大
		public static final int FEETYPE_FIXED_MAX = 1;
		// 按余额比率
		public static final int FEETYPE_RATIO = 2;
		// 费类型
		public int feeType = FEETYPE_FIXED;
		// 固定金额
		public int fixedFee = 0;
		// 余额比率
		public int ratio = 0;
	}

	/**
	 * 获取有效的延期扣费金额
	 * 
	 * @param issueCompany
	 *            发卡商对象
	 * @param cardClassic
	 *            卡种类对象
	 * @return
	 * @throws PCPSApplicationException
	 */
	// private FeeType getValidateExtendExpiredFeeType(IssueCompany
	// issueCompany,
	// CardClassic cardClassic) throws PCPSApplicationException {
	// FeeType feeType = new FeeType();
	//
	// // 取发卡商默认
	// if (PCPSUtil.compareObject(cardClassic.getExtendFeeType(),
	// CardClassic.CARDCLASSIC_EXTEND_FEETYPE_REF_ISSUE)) {
	// if (PCPSUtil.compareObject(issueCompany.getExtendFeeType(),
	// IssueCompany.ISSUECOMPANY_EXTEND_FEETYPE_FIXED))
	// feeType.feeType = FeeType.FEETYPE_FIXED;
	// else if (PCPSUtil.compareObject(issueCompany.getExtendFeeType(),
	// IssueCompany.ISSUECOMPANY_EXTEND_FEETYPE_BALANCE_RATIO))
	// feeType.feeType = FeeType.FEETYPE_RATIO;
	// else
	// throw new PCPSApplicationException("", "发卡商"
	// + issueCompany.getIssueCompanyNo() + "延期扣费模式"
	// + issueCompany.getExtendFeeType() + "无效!");
	// feeType.fixedFee = issueCompany.getExtendFixFee().intValue();
	// feeType.ratio = issueCompany.getExtendFeeRatio().intValue();
	// if (feeType.fixedFee < 0
	// && feeType.feeType == FeeType.FEETYPE_FIXED)
	// throw new PCPSApplicationException("", "发卡商"
	// + issueCompany.getIssueCompanyNo() + "延期扣费固定金额"
	// + issueCompany.getExtendFixFee().toString() + "无效!");
	// if ((feeType.ratio < 0 || feeType.ratio >= 10000)
	// && feeType.feeType == FeeType.FEETYPE_RATIO)
	// throw new PCPSApplicationException("", "发卡商"
	// + issueCompany.getIssueCompanyNo() + "延期扣费按余额比率"
	// + issueCompany.getExtendFeeRatio().toString() + "无效!");
	// return feeType;
	// }
	//
	// if (PCPSUtil.compareObject(cardClassic.getExtendFeeType(),
	// CardClassic.CARDCLASSIC_EXTEND_FEETYPE_FIXED))
	// feeType.feeType = FeeType.FEETYPE_FIXED;
	// else if (PCPSUtil.compareObject(cardClassic.getExtendFeeType(),
	// CardClassic.CARDCLASSIC_EXTEND_FEETYPE_BALANCE_RATIO))
	// feeType.feeType = FeeType.FEETYPE_RATIO;
	// else
	// throw new PCPSApplicationException("", "卡种类"
	// + cardClassic.getCardClassicName() + "延期扣费模式"
	// + cardClassic.getExtendFeeType() + "无效!");
	// feeType.fixedFee = cardClassic.getExtendFixFee().intValue();
	// feeType.ratio = cardClassic.getExtendFeeRatio().intValue();
	// if (feeType.fixedFee < 0 && feeType.feeType == FeeType.FEETYPE_FIXED)
	// throw new PCPSApplicationException("", "卡种类"
	// + cardClassic.getCardClassicName() + "延期扣费固定金额"
	// + cardClassic.getExtendFixFee().toString() + "无效!");
	// if ((feeType.ratio < 0 || feeType.ratio >= 10000)
	// && feeType.feeType == FeeType.FEETYPE_RATIO)
	// throw new PCPSApplicationException("", "卡种类"
	// + cardClassic.getCardClassicName() + "延期扣费按余额比率"
	// + cardClassic.getExtendFeeRatio().toString() + "无效!");
	// return feeType;
	// }
	/**
	 * 获取所有待记帐的卡列表MAP -- 扣费模式
	 * 
	 * @return
	 * @throws PCPSApplicationException
	 */
	private Map<String, ActivateCard> getAllPaidFeeCardMap(PaidParam paidParam)
			throws PCPSApplicationException {
		Map<String, ActivateCard> allcard = new HashMap<String, ActivateCard>();

		// 以锁定方式检查
		for (PaidParam.PaidCardParam pcp : paidParam.allPaidCardList) {
			// 检查卡号
			if (PCPSUtil.isEmpty(pcp.cardNo) || allcard.containsKey(pcp.cardNo))
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_INVALID, "卡号无效!");

			// 检查金额
			if (pcp.amt == null || pcp.amt.compareTo(BigInteger.ZERO) < 0)
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_AMOUNT, "发生额非法!");

			// 手续费
			if (pcp.fee == null)
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_AMOUNT, "手续费非法!");

			// 如果金额为0
			if (pcp.amt.compareTo(BigInteger.ZERO) == 0
					&& pcp.fee.compareTo(BigInteger.ZERO) == 0)
				continue;

			// 检索卡信息
			ActivateCard ac = activateCardDaoImpl
					.getActivateCardByCardNoForUpdate(pcp.cardNo);
			if (ac == null)
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_INVALID, "卡号" + pcp.cardNo + "无效!");

			// 如果有密码,则检查之
			if (!PCPSUtil.isEmpty(pcp.pwd)) {
				if (!ac.VerifyPassword(pcp.pwd))
					throw new CardTranApplicationException(
							TuxedoRespCode.RC_PWDERR, "密码错误!");
			}

			// 判断销卡状态 -- 不等于未销卡
			if (!PCPSUtil.compareObject(ac.getCloseStatus(),
					ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL))
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_INVALID, "卡号已注销!");

			allcard.put(ac.getCardNo(), ac);
		}

		// 必须至少存在1条记录
		if (allcard.size() < 1)
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"必须存在至少1张卡");

		return allcard;
	}

	/**
	 * 批量卡扣费接口
	 * 
	 * @param paidParam
	 *            支付参数
	 * @param summary
	 *            摘要
	 * @throws PCPSApplicationException
	 */
	private PaidResult PaidFee(PaidParam paidParam, String summary)
			throws PCPSApplicationException {
		// 检查入口参数
		if (paidParam == null || PCPSUtil.isEmpty(paidParam.tranSeqNo)
				|| paidParam.tranDate == null
				|| paidParam.allPaidCardList == null
				|| paidParam.allPaidCardList.size() < 1)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_SYS,
					TuxedoRespCode.RC_PARAMETER,
					CardTranApplicationException.ERRMSG_NULLPOINTER);

		// 获取列表
		Map<String, ActivateCard> allcard = getAllPaidFeeCardMap(paidParam);

		ArrayList<AccountParam> accountParamList = new ArrayList<AccountParam>();

		// 生成卡记帐返回列表
		PaidResult paidResult = new PaidResult();

		List<CardAccountParam> caplist = new ArrayList<CardAccountParam>();

		// 生成caplist
		for (PaidParam.PaidCardParam pcp : paidParam.allPaidCardList) {
			CardAccountParam cap = new CardAccountParam();
			cap.cardNo = pcp.cardNo;
			cap.paidAmount = BigInteger.ZERO;
			cap.feeAmount = pcp.fee;
			caplist.add(cap);
		}

		List<CardAccountDetail> all_cad = getCardAccountDetail(caplist);

		// 把all_cad转换成accountParamList
		for (CardAccountDetail cad : all_cad) {
			AccountParam ap = new AccountParam();
			ap.subAccNo = cad.SubAccNo;
			ap.tranType = AccountSystemAddTradDetail.TRANTYPE_FEE;
			ap.summary = "[手续费]" + summary;
			// 全部为借方记帐
			ap.creditAmount = BigInteger.ZERO;
			ap.debitAmount = cad.feeAmount;
			// 加入到记帐列表
			accountParamList.add(ap);
		}

		// 调用核心帐户子系统记帐接口记帐
		paidResult.accseqno = accountBusinessImpl.Account(
				paidParam.issueCompanyNo, paidParam.tranDate, pcpsCommonDaoImpl
						.getDatabaseSysTime(), paidParam.tranSeqNo,
				paidParam.operId, summary, accountParamList);

		// 获取更新后卡余额
		paidResult.cardbalance = getCardBalance(allcard);

		// 返回结果
		return paidResult;
	}

	/**
	 * 卡延期
	 * 
	 * @param eeObj
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public ExtendExpiredObject ExtendExpired(PCPSWebInput webInput,
			ExtendExpiredObject eeObj) throws PCPSApplicationException {
		// 1. 参数检查
		if (eeObj == null || PCPSUtil.isEmpty(eeObj.cardNo)
				|| eeObj.operId == null)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);

		// 2. 非试算时延期备注或原因
		if (!eeObj.isTrail && PCPSUtil.isEmpty(eeObj.remark))
			throw new PCPSApplicationException("", "延期原因为空!");

		// 3. 检查卡相关属性
		ActivateCard ac = getValidateActivateCardByCardNo(eeObj.cardNo);
		// 检查是否能交易
		isCardCanDoTrans(ac);
		// 检查销售机构日终状态
		checkSaleBranchDayOff(webInput.getOperBranchNo());

		// 实名制卡或有效期为空无需延期
		if (ac.getOwnerId() != null || ac.getExpired() == null)
			throw new PCPSApplicationException("", "卡号" + eeObj.cardNo
					+ "无期限限制无需延期!");

		// 取数据库服务器时间
		Date curSysDate = pcpsCommonDaoImpl.getDatabaseSysTime();

		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(eeObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new PCPSApplicationException("", "操作员无效!");

		// 操作员对应的发卡商号
		String oper_IssueCompanyNo = PCPSUtil.getICNoByBranchNo(sysOpUser
				.getOperBranchNo());

		// 检索制卡控制批次
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(ac.getBatchNo());

		// 取卡系统全局数据字典
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(mcc.getIssueCompanyNo());

		// 操作员与卡的归属必须是同一发卡商
		if (!PCPSUtil.compareObject(oper_IssueCompanyNo, issueCompany
				.getIssueCompanyNo()))
			throw new PCPSApplicationException("", "卡不存在!");

		// 设置新有效期,取发卡商卡延期时间单位
		eeObj.newExpired = PCPSUtil.getDateYMDByString(PCPSUtil.BeforeNowMonth(
				ac.getExpired(), issueCompany.getDefaultExpired()));

		if (eeObj.newExpired.compareTo(ac.getExpired()) <= 0)
			throw new PCPSApplicationException("", "卡号" + eeObj.cardNo
					+ "新到期日期不能比现有有效期早!");
		if (eeObj.newExpired.compareTo(curSysDate) <= 0)
			throw new PCPSApplicationException("", "卡号" + eeObj.cardNo
					+ "新到期日期不能比当前日期早!");

		// 计算费用
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_CardExpired, ac.getCardNo(),
				null, issueCompany.getTranDate(), ac.getBalance());

		BigInteger fee = ifp.getFee();

		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_CardExpired);

		// 设置返回余额
		eeObj.balance = ac.getBalance();
		eeObj.fee = fee;

		// 如果是试算,把试算结果返回
		if (eeObj.isTrail) {
			return eeObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !eeObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}

		// 检查收费模式
		if (!PCPSUtil.compareObject(eeObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(eeObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");

		// 检查优惠的手续费
		if ((eeObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(eeObj.discountFee) > 0
				|| eeObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (eeObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(eeObj.authOperId, eeObj.authPwd, eeObj.operId,
					sysOpUser.getOperBranchNo());
		else
			eeObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(eeObj.discountFee);

		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(eeObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			eeObj.cashFee = BigInteger.ZERO;
			eeObj.cardFee = factfee;
		} else {
			eeObj.cashFee = factfee;
			eeObj.cardFee = BigInteger.ZERO;
		}

		// 原始到期日
		Date oldExpired = ac.getExpired();

		// 执行延期
		ac.setExpired(eeObj.newExpired);
		activateCardDaoImpl.update(ac);

		// 卡事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		String accSeqNo = null;

		// 如果需要延期,则执行扣费动作
		if (eeObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = eeObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = eeObj.cardNo;
			pcp.pwd = eeObj.pwd;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = eeObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "延期手续费");

			// 保留流水号
			accSeqNo = paidResult.accseqno;

			// 设置返回余额
			eeObj.balance = paidResult.cardbalance.get(eeObj.cardNo);
		}

		// 现金收入记帐
		if (eeObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					eeObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid, eeObj.operId,
					curSysDate, "延期手续费");

		// 单号
		Integer seqNo = sysBranchDaoImpl.updateSysBranchOrderSeqNo(sysOpUser
				.getOperBranchNo());
		String cardEventOrderSeq = sysOpUser.getOperBranchNo()
				+ PCPSUtil.getPackedYMDString(issueCompany.getTranDate())
				+ String.format("%05d", seqNo);
		eeObj.orderSeqNo = evid.toString();// 返回的CardEventId
		// 记载卡延期事件日志
		CardEventLog cel = new CardEventLog();

		cel.setBalance(eeObj.balance);
		cel.setFee(fee);
		cel.setCardFee(eeObj.cardFee);
		cel.setCashFee(eeObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(eeObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(eeObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(eeObj.operId);
		cel.setRemark(eeObj.remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(ac.getCardNo());
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setExpired(oldExpired);
		cel.setNewExpired(eeObj.newExpired);
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(curSysDate);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_MODIFY_EXPIRED);

		cardEventLogDaoImpl.insert(cel);
		return eeObj;
	}

	/**
	 * 单卡销售机构现金充值入口参数检查
	 * 
	 * @param depositObject
	 * @throws PCPSApplicationException
	 */
	private void checkCashDepostArgs(CashDepositObject depositObject)
			throws PCPSApplicationException {
		// 入口参数检查
		if (depositObject == null)
			throw new PCPSApplicationException("", "单卡销售机构现金充值参数为空!");

		if (PCPSUtil.isEmpty(depositObject.cardNo))
			throw new PCPSApplicationException("", "卡号为空!");

		if (depositObject.amount == null
				|| BigInteger.ZERO.compareTo(depositObject.amount) >= 0)
			throw new PCPSApplicationException("", "非法的充值金额!");

		if (depositObject.operId == null)
			throw new PCPSApplicationException("", "操作员ID为空!");
	}

	/**
	 * 创建现金充值单
	 * 
	 * @param ac
	 * @param sysOpUser
	 * @param depositObject
	 * @return
	 * @throws PCPSApplicationException
	 */
	private DepositOrder createCashDepositOrder(ActivateCard ac,
			SysOpUser sysOpUser, CashDepositObject depositObject)
			throws PCPSApplicationException {
		// 1. 创建现金充值单
		DepositOrder depositOrder = new DepositOrder();

		depositOrder.setDepositOrderId(pcpsCommonDaoImpl.getUniqueIntegerKey());
		depositOrder.setSaleBranchNo(sysOpUser.getOperBranchNo());
		depositOrder.setBuyerType(DepositOrder.DEPORDER_BUYERTYPE_PERSON);
		depositOrder.setPersonalBuyerId(ac.getOwnerId());
		depositOrder.setOrganizeBuyerId(null);
		depositOrder.setProxyBuyerId(null);
		depositOrder.setDepositTime(pcpsCommonDaoImpl.getDatabaseSysTime());
		depositOrder.setTotalDepositAmount(depositObject.amount);
		depositOrder.setAlreayPaidAmount(depositObject.amount);
		depositOrder.setDepositType(DepositOrder.DEPORDER_DEPOSITTYPE_ONE);
		depositOrder
				.setOrderStatus(DepositOrder.DEPORDER_ORDERSTATUS_HAVERECHARGE);
		depositOrder.setLastDepositMac(null);
		depositOrder.setLastDepositAccSeqNo(null);
		depositOrder.setLastCancelDepositAccSeqNo(null);
		depositOrder.setOperId(depositObject.operId);
		depositOrder.setAuthOperId(depositObject.operId);
		depositOrder.setRiskRemark(null);
		depositOrder.setRemark(null);

		depositOrderDaoImpl.insertDepositOrder(depositOrder);

		// 2. 创建充值单充值明细
		DepositOrderDetail depositOrderDetail = new DepositOrderDetail();

		depositOrderDetail.setDepositOrderId(depositOrder.getDepositOrderId());
		depositOrderDetail.setBatchNo(ac.getBatchNo());
		depositOrderDetail.setCardSeqNo(ac.getCardSeqNo());
		depositOrderDetail.setCardNo(ac.getCardNo());
		depositOrderDetail.setCustomId(ac.getOwnerId());
		depositOrderDetail.setDepositAmount(depositObject.amount);

		depositOrderDetailDaoImpl.insertDepositOrderDetail(depositOrderDetail);

		// 3. 创建充值单付款信息
		DepositOrderPaidDetail depositOrderPaidDetail = new DepositOrderPaidDetail();

		depositOrderPaidDetail.setDepositOrderPaidId(pcpsCommonDaoImpl
				.getUniqueIntegerKey());
		depositOrderPaidDetail.setTranTime(depositOrder.getDepositTime());
		depositOrderPaidDetail.setDepositOrderId(depositOrder
				.getDepositOrderId());
		depositOrderPaidDetail
				.setPaidType(DepositOrderPaidDetail.DEPOSITOPD_PAIDTYPE_CASH);
		depositOrderPaidDetail.setPaidAmount(depositObject.amount);
		depositOrderPaidDetail.setPayeeAccountId(null);
		depositOrderPaidDetail.setPaidAccountId(null);
		depositOrderPaidDetail.setVoucherNo(null);
		depositOrderPaidDetail.setVoucherRemark(null);
		depositOrderPaidDetail.setVoucherImageId(null);
		depositOrderPaidDetail.setOperId(depositObject.operId);
		depositOrderPaidDetail.setCancelDepositOrderPaidId(null);
		depositOrderPaidDetail.setRemark(null);

		depositOrderPaidDetailDaoImpl
				.insertDepositOrderPaidDetail(depositOrderPaidDetail);

		// 4. 创建充值单状态转换明细
		DepositOrderActionDetail depositOrderActionDetail = new DepositOrderActionDetail();

		depositOrderActionDetail.setDepositOrderId(depositOrder
				.getDepositOrderId());
		depositOrderActionDetail.setActionTime(depositOrder.getDepositTime());
		depositOrderActionDetail.setOperId(depositObject.operId);
		depositOrderActionDetail
				.setInitialStatus(DepositOrder.DEPORDER_ORDERSTATUS_INPUT);
		depositOrderActionDetail
				.setEndStatus(DepositOrder.DEPORDER_ORDERSTATUS_HAVERECHARGE);
		depositOrderActionDetail
				.setActionType(DepositOrderActionDetail.DEPOSITOAD_ACTIONTYPE_AUDIT);
		depositOrderActionDetail.setRemark(null);

		depositOrderActionDetailDaoImpl
				.insertDepositOrderActionDetail(depositOrderActionDetail);

		return depositOrder;
	}

	/**
	 * 销售机构信用度记帐
	 * 
	 * @param saleBranch
	 * @param tranDate
	 * @param depositAmount
	 * @param withdrawAmount
	 * @param ticketId
	 * @param operId
	 */
	@SuppressWarnings("unused")
	private SaleBranch saleBranchCaptialAccountOnlyCredit(String saleBranchNo,
			Date tranDate, BigInteger depositAmount, BigInteger withdrawAmount,
			String tranType, BigInteger ticketId, BigInteger operId,
			Date curTime, String remark) throws PCPSApplicationException {

		// 检索
		SaleBranch saleBranch = saleBranchDaoImpl
				.getSaleBranchBySaleBranchNo(saleBranchNo);

		// 更新信用度余额
		BigInteger creditbal = saleBranch.getCredit().add(depositAmount)
				.subtract(withdrawAmount);
		if (creditbal.compareTo(saleBranch.getCreditLowLimit()) < 0)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					"", "销售机构" + saleBranch.getSaleBranchNo() + "信用度不足!");

		saleBranch.setCredit(creditbal);
		saleBranchDaoImpl.updateSaleBranch(saleBranch);

		// 记录机构资金明细
		SaleCapitalDetail saleCapitalDetail = new SaleCapitalDetail();

		saleCapitalDetail.setSaleBranchNo(saleBranch.getSaleBranchNo());
		saleCapitalDetail.setTranDate(tranDate);
		saleCapitalDetail.setTranTime(curTime);
		saleCapitalDetail.setTranType(tranType);
		saleCapitalDetail.setTicketId(ticketId);
		saleCapitalDetail.setCreditDeposit(depositAmount);
		saleCapitalDetail.setCreditWithdraw(withdrawAmount);
		saleCapitalDetail.setCashDeposit(BigInteger.ZERO);
		saleCapitalDetail.setCashWithdraw(BigInteger.ZERO);
		saleCapitalDetail.setOperId(operId);
		saleCapitalDetail.setRemark(remark);

		saleCapitalDetailDaoImpl.insertSaleCapitalDetail(saleCapitalDetail);

		return saleBranch;
	}

	/**
	 * 销售机构信用度&现金记帐
	 * 
	 * @param saleBranch
	 * @param tranDate
	 * @param depositAmount
	 * @param withdrawAmount
	 * @param cashDeposit
	 * @param cashWithdraw
	 * @param saleOrderId
	 * @param activeOrderId
	 * @param operId
	 */
	private SaleBranch saleBranchCaptialAccount(String saleBranchNo,
			Date tranDate, BigInteger depositAmount, BigInteger withdrawAmount,
			BigInteger cashDeposit, BigInteger cashWithdraw, String tranType,
			BigInteger ticketId, BigInteger operId, Date curTime, String remark)
			throws PCPSApplicationException {

		// 检索
		SaleBranch saleBranch = saleBranchDaoImpl
				.getSaleBranchBySaleBranchNo(saleBranchNo);

		// 更新信用度余额
		BigInteger creditbal = saleBranch.getCredit().add(depositAmount)
				.subtract(withdrawAmount);
		if (creditbal.compareTo(saleBranch.getCreditLowLimit()) < 0)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					"", "销售机构" + saleBranch.getSaleBranchNo() + "信用度不足!");

		BigInteger cashbal = saleBranch.getCash().add(cashDeposit).subtract(
				cashWithdraw);

		saleBranch.setCash(cashbal);
		saleBranch.setCredit(creditbal);
		saleBranchDaoImpl.updateSaleBranch(saleBranch);

		// 记录机构资金明细
		SaleCapitalDetail saleCapitalDetail = new SaleCapitalDetail();

		saleCapitalDetail.setSaleBranchNo(saleBranch.getSaleBranchNo());
		saleCapitalDetail.setTranDate(tranDate);
		saleCapitalDetail.setTranTime(curTime);
		saleCapitalDetail.setTranType(tranType);
		saleCapitalDetail.setTicketId(ticketId);
		saleCapitalDetail.setCreditDeposit(depositAmount);
		saleCapitalDetail.setCreditWithdraw(withdrawAmount);
		saleCapitalDetail.setCashDeposit(cashDeposit);
		saleCapitalDetail.setCashWithdraw(cashWithdraw);
		saleCapitalDetail.setOperId(operId);
		saleCapitalDetail.setRemark(remark);

		saleCapitalDetailDaoImpl.insertSaleCapitalDetail(saleCapitalDetail);

		return saleBranch;
	}

	/**
	 * 机构现金库超限预警提示
	 * 
	 * @param saleBranch
	 * @param issueCompany
	 * @return
	 */
	private String saleCashLimitHint(SaleBranch saleBranch,
			IssueCompany issueCompany) {

		BigInteger percent = BigInteger.valueOf(100);
		String lim = issueCompany.getCashUpperLimit().divide(percent)
				.toString();
		String cur = saleBranch.getCash().divide(percent).toString();

		if (issueCompany.getCashUpperLimit().compareTo(BigInteger.ZERO) > 0
				&& saleBranch.getCash().compareTo(
						issueCompany.getCashUpperLimit()) > 0)
			return "你机构现金库为" + cur + "元,中心预警限额为" + lim + "元,请尽快上缴!";

		return "";
	}

	/**
	 * 计算单卡现金充值单激活MAC
	 * 
	 * @param depositOrderId
	 * @param balance
	 * @param accSeqNo
	 * @param operId
	 * @return
	 */
	private String getDepositOrderActivateMac(BigInteger depositOrderId,
			String accSeqNo, BigInteger operId, BigInteger balance) {
		String macsrc = depositOrderId.toString() + accSeqNo
				+ operId.toString() + balance.toString();
		return new SHA1().getDigestOfString(macsrc.getBytes());
	}

	/**
	 * 验证卡的最大可充值额度
	 * 
	 * @param mrchDepositObject
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public MrchDepositObject MrchDepositValidate(
			MrchDepositObject mrchDepositObject)
			throws PCPSApplicationException {
		// 检索卡信息
		ActivateCard ac = getValidateActivateCardByCardNo(mrchDepositObject.cardNo);

		// 判断销卡状态 -- 不等于未销卡
		if (!PCPSUtil.compareObject(ac.getCloseStatus(),
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡" + mrchDepositObject.cardNo + "已经注销!");

		// 判断挂失状态 -- 等于正式挂失或者临时挂失
		if (PCPSUtil.compareObject(ac.getLossStatus(),
				ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED)
				|| PCPSUtil.compareObject(ac.getLossStatus(),
						ActivateCard.ACTIVATECARD_LOSSSTATUS_TEMP_LOSSED))
			throw new CardTranApplicationException(TuxedoRespCode.RC_LOSSED,
					"卡" + mrchDepositObject.cardNo + "已经挂失!");

		// 检索制卡控制批次
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(ac.getBatchNo());

		// 取卡种类
		CardClassic cardClassic = cardClassicDaoImpl
				.getCardClassicByCardClassicId(ac.getCardClassicId());

		// 取卡种类是否允许充值
		if (!PCPSUtil.compareObject(cardClassic.getAllowDeposit(),
				CardClassic.CARDCLASSIC_ALLOWDEPOSIT_RECHARGE))
			throw new CardTranApplicationException(
					TuxedoRespCode.RC_CARDHOLDER_LIMIT, "卡种类["
							+ cardClassic.getCardClassicName() + "]不允许充值!");

		// 取卡系统全局数据字典
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(mcc.getIssueCompanyNo());

		// 商户与卡的归属必须是同一发卡商
		if (!PCPSUtil.compareObject(mrchDepositObject.issueCompanyNo,
				issueCompany.getIssueCompanyNo()))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"非本发卡商发行的卡!");

		// 取系统余额限制参数
		BigInteger ballim = cardClassic.getBalanceLimit();
		int result = BigInteger.ZERO.compareTo(ballim);
		if (result > 0)
			throw new CardTranApplicationException(TuxedoRespCode.RC_LIMIT,
					"卡种类[" + cardClassic.getCardClassicName() + "]余额限制参数非法!");
		if (result == 0)
			ballim = issueCompany.getEachCardBalanceLimit();

		result = BigInteger.ZERO.compareTo(ballim);
		if (result > 0)
			throw new CardTranApplicationException(TuxedoRespCode.RC_LIMIT,
					"发卡商[" + issueCompany.getIssueCompanyNo() + "]余额限制参数非法!");

		// 假定充值无限制
		mrchDepositObject.depositLimit = BigInteger.ZERO
				.subtract(BigInteger.ONE);

		// 如果存在总额限制
		if (result < 0) {
			if (ballim.compareTo(ac.getBalance()) <= 0)
				throw new CardTranApplicationException(TuxedoRespCode.RC_LIMIT,
						"余额限制参数比现有卡余额小!");
			mrchDepositObject.depositLimit = PCPSUtil.setValidateLimit(
					mrchDepositObject.depositLimit, ballim.subtract(ac
							.getBalance()));
		}

		// 充值金额是否超现金充值上限
		if (issueCompany.getDepositTransferLimit().compareTo(BigInteger.ZERO) > 0)
			mrchDepositObject.depositLimit = PCPSUtil.setValidateLimit(
					mrchDepositObject.depositLimit, issueCompany
							.getDepositTransferLimit());

		// 本次充值后金额超限检查 -- 实名制
		if (issueCompany.getEachCardOwnerLimit().compareTo(BigInteger.ZERO) > 0
				&& ac.getOwnerId() == null) {
			if (issueCompany.getEachCardOwnerLimit().compareTo(ac.getBalance()) <= 0)
				throw new CardTranApplicationException(TuxedoRespCode.RC_LIMIT,
						"实名制余额限制参数比现有卡余额小!");
			mrchDepositObject.depositLimit = PCPSUtil.setValidateLimit(
					mrchDepositObject.depositLimit, issueCompany
							.getEachCardOwnerLimit().subtract(ac.getBalance()));
		}

		return mrchDepositObject;
	}

	/**
	 * 单卡商户充值
	 * 
	 * @param mrchDepositObject
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public MrchDepositObject MrchDeposit(MrchDepositObject mrchDepositObject)
			throws PCPSApplicationException {
		// 1. 交易检查阶段

		// 检索卡信息
		ActivateCard ac = getValidateActivateCardByCardNo(mrchDepositObject.cardNo);

		// 判断销卡状态 -- 不等于未销卡
		if (!PCPSUtil.compareObject(ac.getCloseStatus(),
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡" + mrchDepositObject.cardNo + "已经注销!");

		// 判断挂失状态 -- 等于正式挂失或者临时挂失
		if (PCPSUtil.compareObject(ac.getLossStatus(),
				ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED)
				|| PCPSUtil.compareObject(ac.getLossStatus(),
						ActivateCard.ACTIVATECARD_LOSSSTATUS_TEMP_LOSSED))
			throw new CardTranApplicationException(TuxedoRespCode.RC_LOSSED,
					"卡" + mrchDepositObject.cardNo + "已经挂失!");

		// 检索制卡控制批次
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(ac.getBatchNo());

		// 取卡种类
		CardClassic cardClassic = cardClassicDaoImpl
				.getCardClassicByCardClassicId(ac.getCardClassicId());

		// 取卡种类是否允许充值
		if (!PCPSUtil.compareObject(cardClassic.getAllowDeposit(),
				CardClassic.CARDCLASSIC_ALLOWDEPOSIT_RECHARGE))
			throw new CardTranApplicationException(
					TuxedoRespCode.RC_CARDHOLDER_LIMIT, "卡种类["
							+ cardClassic.getCardClassicName() + "]不允许充值!");

		// 取卡系统全局数据字典
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(mcc.getIssueCompanyNo());

		// 商户与卡的归属必须是同一发卡商
		if (!PCPSUtil.compareObject(mrchDepositObject.issueCompanyNo,
				issueCompany.getIssueCompanyNo()))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"非本发卡商发行的卡!");

		// 充值金额是否超限
		if (issueCompany.getDepositTransferLimit().compareTo(BigInteger.ZERO) > 0
				&& mrchDepositObject.amount.compareTo(issueCompany
						.getDepositTransferLimit()) > 0)
			throw new CardTranApplicationException(TuxedoRespCode.RC_AMOUNT,
					"充值金额超限,请在销售点用转账方式充值!");

		// 本次充值后金额超限检查
		BigInteger newbal = ac.getBalance().add(mrchDepositObject.amount);
		if (issueCompany.getEachCardOwnerLimit().compareTo(BigInteger.ZERO) > 0
				&& newbal.compareTo(issueCompany.getEachCardOwnerLimit()) > 0
				&& ac.getOwnerId() == null)
			throw new CardTranApplicationException(
					TuxedoRespCode.RC_CARDHOLDER_LIMIT, "充值后余额超限,请登记实名持卡人信息!");

		// 余额超限检查
		checkBalanceLimit(mrchDepositObject.cardNo, newbal, issueCompany,
				cardClassic);

		// 2. 帐户子系统记帐
		ac = activateCardDaoImpl.getActivateCardByCardNoForUpdate(ac
				.getCardNo());

		// 充值前余额
		mrchDepositObject.beforeBalance = ac.getBalance();

		// ArrayList<SalesGroup> salesList = new ArrayList<SalesGroup>();
		ArrayList<AccountParam> accountParamList = new ArrayList<AccountParam>();

		List<SubAccount> saclist = subAccountDaoImpl
				.getAllSubAccountForPaidByMasterAccNo(ac.getMasterAccNo());
		SubAccount sac = saclist.get(0);

		AccountParam ap = new AccountParam();
		ap.subAccNo = sac.getSubAccNo();
		ap.creditAmount = mrchDepositObject.amount;
		ap.debitAmount = BigInteger.ZERO;
		ap.tranType = AccountSystemAddTradDetail.TRANTYPE_DEPOSIT;
		ap.summary = "充值";
		accountParamList.add(ap);

		if (mrchDepositObject.fee == null)
			mrchDepositObject.fee = BigInteger.ZERO;

		if (!BigInteger.ZERO.equals(mrchDepositObject.fee)) {
			ap = new AccountParam();
			ap.subAccNo = sac.getSubAccNo();
			ap.creditAmount = BigInteger.ZERO;
			ap.debitAmount = mrchDepositObject.fee;
			ap.tranType = AccountSystemAddTradDetail.TRANTYPE_FEE;
			ap.summary = "手续费";
			accountParamList.add(ap);
		}

		// 执行核心记帐
		String accSeqNo = accountBusinessImpl.Account(issueCompany
				.getIssueCompanyNo(), mrchDepositObject.tranDate,
				mrchDepositObject.tranTime, mrchDepositObject.tranSeqNo, null,
				mrchDepositObject.remark, accountParamList);

		// 5. 更新卡累计充值额
		ac = activateCardDaoImpl.getActivateCardByCardNoForUpdate(ac
				.getCardNo());
		ac.setTotalDeposit(ac.getTotalDeposit().add(mrchDepositObject.amount));
		activateCardDaoImpl.update(ac);

		// 充值后余额

		mrchDepositObject.accSeqNo = accSeqNo;
		mrchDepositObject.afterBalance = ac.getBalance();
		mrchDepositObject.masterAccNo = ac.getMasterAccNo();
		mrchDepositObject.subAccNo = sac.getSubAccNo();
		mrchDepositObject.saleBranchNo = ac.getOpenBranchNo();

		return mrchDepositObject;
	}

	/**
	 * 单卡商户充值撤销
	 * 
	 * @param mrchDepositObject
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public MrchDepositObject CancelMrchDeposit(
			MrchDepositObject mrchDepositObject)
			throws PCPSApplicationException {

		// 取原始记帐记录
		List<AccountSystemAddTradDetail> astdlist = accountSystemAddTradDetailDaoImpl
				.getAllAccountSystemAddTradDetailByAccSeqNo(mrchDepositObject.cancelAccSeqNo);

		if (astdlist == null || astdlist.size() != 1)
			throw new CardTranApplicationException(TuxedoRespCode.RC_NONEXIST,
					"原交易未找到!");

		// 此处不用原流水中的卡号的原因是,有可能此间卡号挂失补发了,因此以主帐户当前的卡号为准
		BigInteger masaccno = astdlist.get(0).getMasterAccNo();
		MasterAccount macc = masterAccountDaoImpl
				.getMasterAccountByMasterAccNo(masaccno);
		if (macc == null || PCPSUtil.isEmpty(macc.getCardNo()))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡号无效!");
		String cardNo = macc.getCardNo();

		ActivateCard ac = getValidateActivateCardByCardNo(cardNo);

		// 判断销卡状态 -- 不等于未销卡
		if (!PCPSUtil.compareObject(ac.getCloseStatus(),
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡号[NEW:" + cardNo + ",OLD:" + astdlist.get(0).getCardNo()
							+ "]已经销卡");

		mrchDepositObject.beforeBalance = ac.getBalance();

		// 商户
		Merchant mrch = merchantDaoImpl
				.getMerchantByMerchantNo(mrchDepositObject.merchantNo);
		if (mrch == null)
			throw new CardTranApplicationException(
					TuxedoRespCode.RC_NOMERCHANT, "无效商户!");

		// 生成业务摘要
		String summary = "[充值冲正]" + mrch.getMerchantName();

		mrchDepositObject.accSeqNo = accountBusinessImpl.AccountCancel(
				mrchDepositObject.issueCompanyNo, mrchDepositObject.tranDate,
				mrchDepositObject.tranTime, mrchDepositObject.tranSeqNo,
				mrchDepositObject.cancelAccSeqNo, null, summary);

		// 重新检索主帐号信息
		macc = masterAccountDaoImpl
				.getMasterAccountByMasterAccNoForUpdate(masaccno);

		BigInteger diff = macc.getBalance().subtract(
				mrchDepositObject.beforeBalance);

		// 更新卡余额
		ac = activateCardDaoImpl.getActivateCardByCardNoForUpdate(ac
				.getCardNo());
		ac.setTotalDeposit(ac.getTotalDeposit().add(diff));
		activateCardDaoImpl.update(ac);

		// 充值撤销后余额
		mrchDepositObject.afterBalance = ac.getBalance();
		mrchDepositObject.masterAccNo = ac.getMasterAccNo();
		mrchDepositObject.subAccNo = astdlist.get(0).getSubAccNo();

		return mrchDepositObject;
	}

	/**
	 * 单卡商户充值重做
	 * 
	 * @param mrchDepositObject
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public MrchDepositObject redoMrchDeposit(MrchDepositObject mrchDepositObject)
			throws PCPSApplicationException {

		// 取原始记帐记录
		List<AccountSystemAddTradDetail> astdlist = accountSystemAddTradDetailDaoImpl
				.getAllAccountSystemAddTradDetailByAccSeqNo(mrchDepositObject.redoAccSeqNo);

		if (astdlist == null || astdlist.size() != 1)
			throw new CardTranApplicationException(TuxedoRespCode.RC_NONEXIST,
					"原交易未找到!");

		// 此处不用原流水中的卡号的原因是,有可能此间卡号挂失补发了,因此以主帐户当前的卡号为准
		BigInteger masaccno = astdlist.get(0).getMasterAccNo();
		MasterAccount macc = masterAccountDaoImpl
				.getMasterAccountByMasterAccNo(masaccno);
		if (macc == null || PCPSUtil.isEmpty(macc.getCardNo()))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡号无效!");
		String cardNo = macc.getCardNo();

		ActivateCard ac = getValidateActivateCardByCardNo(cardNo);

		// 判断销卡状态 -- 不等于未销卡
		if (!PCPSUtil.compareObject(ac.getCloseStatus(),
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡号[NEW:" + cardNo + ",OLD:" + astdlist.get(0).getCardNo()
							+ "]已经销卡");

		mrchDepositObject.beforeBalance = ac.getBalance();

		// 商户
		Merchant mrch = merchantDaoImpl
				.getMerchantByMerchantNo(mrchDepositObject.merchantNo);
		if (mrch == null)
			throw new CardTranApplicationException(
					TuxedoRespCode.RC_NOMERCHANT, "无效商户!");

		// 生成业务摘要
		String summary = "[重做充值]" + mrch.getMerchantName();

		mrchDepositObject.accSeqNo = accountBusinessImpl.redoAccount(
				mrchDepositObject.issueCompanyNo, mrchDepositObject.tranDate,
				mrchDepositObject.tranTime, mrchDepositObject.tranSeqNo,
				mrchDepositObject.redoAccSeqNo, null, summary);

		// 重新检索主帐号信息
		macc = masterAccountDaoImpl
				.getMasterAccountByMasterAccNoForUpdate(masaccno);

		BigInteger diff = macc.getBalance().subtract(
				mrchDepositObject.beforeBalance);

		// 更新卡余额
		ac = activateCardDaoImpl.getActivateCardByCardNoForUpdate(ac
				.getCardNo());
		ac.setTotalDeposit(ac.getTotalDeposit().add(diff));
		activateCardDaoImpl.update(ac);

		// 充值撤销后余额
		mrchDepositObject.afterBalance = ac.getBalance();
		mrchDepositObject.masterAccNo = ac.getMasterAccNo();
		mrchDepositObject.subAccNo = astdlist.get(0).getSubAccNo();

		return mrchDepositObject;
	}

	/**
	 * 单卡销售机构现金充值
	 * 
	 * @param depositObject
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public CashDepositObject CashDeposit(PCPSWebInput webInput,
			CashDepositObject depositObject) throws PCPSApplicationException {

		// 1. 交易检查阶段

		// 入口参数检查
		checkCashDepostArgs(depositObject);

		// 检索卡信息
		ActivateCard ac = getValidateActivateCardByCardNo(depositObject.cardNo);

		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(depositObject.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new PCPSApplicationException("", "操作员无效!");

		// 操作员必须是销售机构的操作员
		SaleBranch saleBranch = saleBranchDaoImpl
				.getSaleBranchBySaleBranchNo(sysOpUser.getOperBranchNo());
		if (saleBranch == null)
			throw new PCPSApplicationException("", "非销售机构的操作员!");

		// 操作员对应的发卡商号
		String oper_IssueCompanyNo = PCPSUtil.getICNoByBranchNo(sysOpUser
				.getOperBranchNo());

		// 判断销卡状态 -- 不等于未销卡
		if (!PCPSUtil.compareObject(ac.getCloseStatus(),
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡" + depositObject.cardNo + "已经注销!");

		// 判断挂失状态 -- 等于正式挂失或者临时挂失
		if (PCPSUtil.compareObject(ac.getLossStatus(),
				ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED)
				|| PCPSUtil.compareObject(ac.getLossStatus(),
						ActivateCard.ACTIVATECARD_LOSSSTATUS_TEMP_LOSSED))
			throw new CardTranApplicationException(TuxedoRespCode.RC_LOSSED);

		// 检索制卡控制批次
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(ac.getBatchNo());

		// 取卡种类
		CardClassic cardClassic = cardClassicDaoImpl
				.getCardClassicByCardClassicId(ac.getCardClassicId());

		// 取卡种类是否允许充值
		if (!PCPSUtil.compareObject(cardClassic.getAllowDeposit(),
				CardClassic.CARDCLASSIC_ALLOWDEPOSIT_RECHARGE))
			throw new PCPSApplicationException("", "卡种类["
					+ cardClassic.getCardClassicName() + "]不允许充值!");

		// 取卡系统全局数据字典
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(mcc.getIssueCompanyNo());

		// 操作员与卡的归属必须是同一发卡商
		if (!PCPSUtil.compareObject(oper_IssueCompanyNo, issueCompany
				.getIssueCompanyNo()))
			throw new PCPSApplicationException("", "卡不存在!");

		// 充值金额是否超限
		if (issueCompany.getDepositTransferLimit().compareTo(BigInteger.ZERO) > 0
				&& depositObject.amount.compareTo(issueCompany
						.getDepositTransferLimit()) > 0)
			throw new PCPSApplicationException("", "充值金额超限,请用转账方式充值!");

		// 本次充值后金额超限检查
		BigInteger newbal = ac.getBalance().add(depositObject.amount);
		if (issueCompany.getEachCardOwnerLimit().compareTo(BigInteger.ZERO) > 0
				&& newbal.compareTo(issueCompany.getEachCardOwnerLimit()) > 0
				&& ac.getOwnerId() == null)
			throw new PCPSApplicationException("", "充值后余额超限,请登记实名持卡人信息!");

		// 余额超限检查
		checkBalanceLimit(depositObject.cardNo, newbal, issueCompany,
				cardClassic);

		// 销售机构信用度检查
		newbal = saleBranch.getCredit().subtract(depositObject.amount);
		if (newbal.compareTo(saleBranch.getCreditLowLimit()) < 0)
			throw new PCPSApplicationException("", "你机构在中心信用度/预存款余额不足,请补充!");

		// 2. 创建充值单相关信息
		DepositOrder depositOrder = createCashDepositOrder(ac, sysOpUser,
				depositObject);

		// 置返回的充值单ID
		depositObject.depositOrderId = depositOrder.getDepositOrderId();

		// 3. 机构信用度&现金记帐
		saleBranch = saleBranchCaptialAccount(saleBranch.getSaleBranchNo(),
				issueCompany.getTranDate(), BigInteger.ZERO,
				depositObject.amount, depositObject.amount, BigInteger.ZERO,
				SaleCapitalDetail.TRANTYPE_CASH_DEPOSIT, depositOrder
						.getDepositOrderId(), depositObject.operId,
				depositOrder.getDepositTime(), depositObject.cardNo + "现金充值");

		// 产生现金超限预警提示
		depositObject.cashLimitMessage = saleCashLimitHint(saleBranch,
				issueCompany);

		// 4. 帐户子系统记帐
		ac = activateCardDaoImpl.getActivateCardByCardNoForUpdate(ac
				.getCardNo());

		// 充值前余额
		depositObject.beforeBalance = ac.getBalance();

		ArrayList<SalesGroup> salesList = new ArrayList<SalesGroup>();
		ArrayList<DepositAccountParam> depositAccountParamList = new ArrayList<DepositAccountParam>();

		DepositAccountParam ap = new DepositAccountParam();
		ap.masterAccNo = ac.getMasterAccNo();
		ap.depositAmount = depositObject.amount;
		ap.remark = "现金充值";

		depositAccountParamList.add(ap);

		DepositAccountResult dar = accountBusinessImpl.DepositAccount(
				issueCompany.getIssueCompanyNo(), saleBranch.getSaleBranchNo(),
				depositOrder.getDepositOrderId(), issueCompany.getTranDate(),
				depositOrder.getDepositTime(), "DEPOSIT_"
						+ depositOrder.getDepositOrderId().toString(),
				depositObject.operId, "现金充值", depositAccountParamList,
				salesList, null);

		// 保存记帐流水号
		depositObject.accSeqNo = dar.accSeqNo;

		// 5. 更新卡余额&累计充值额
		ac = activateCardDaoImpl.getActivateCardByCardNoForUpdate(ac
				.getCardNo());
		ac.setTotalDeposit(ac.getTotalDeposit().add(depositObject.amount));
		activateCardDaoImpl.update(ac);

		// 充值后余额
		depositObject.afterBalance = ac.getBalance();

		// 6. 更新充值单记帐流水号
		depositOrder.setLastDepositAccSeqNo(depositObject.accSeqNo);
		String macstr = getDepositOrderActivateMac(depositOrder
				.getDepositOrderId(), depositObject.accSeqNo,
				depositObject.operId, depositObject.afterBalance);
		depositOrder.setLastDepositMac(macstr);
		depositOrderDaoImpl.updateDepositOrder(depositOrder);

		return depositObject;
	}

	/**
	 * 单卡销售机构现金充值撤销入口参数检查
	 * 
	 * @param depositObject
	 * @throws PCPSApplicationException
	 */
	private void checkCancelCashDepostArgs(CashDepositObject depositObject)
			throws PCPSApplicationException {
		// 入口参数检查
		if (depositObject == null)
			throw new PCPSApplicationException("", "单卡销售机构现金充值撤销参数为空!");

		if (depositObject.amount == null
				|| BigInteger.ZERO.compareTo(depositObject.amount) >= 0)
			throw new PCPSApplicationException("", "非法的撤销充值金额!");

		if (depositObject.operId == null)
			throw new PCPSApplicationException("", "操作员ID为空!");

		if (depositObject.cancelDepositOrderId == null)
			throw new PCPSApplicationException("", "撤销充值单ID为空!");

		if (PCPSUtil.isEmpty(depositObject.remark))
			throw new PCPSApplicationException("", "必须填写撤销原因!");
	}

	/**
	 * 撤销现金充值单
	 * 
	 * @param depositOrder
	 * @param tranTime
	 * @throws PCPSApplicationException
	 */
	private void cancelCashDepositOrder(DepositOrder depositOrder,
			Date tranTime, CashDepositObject depositObject)
			throws PCPSApplicationException {
		// 1. 创建充值单付款撤销信息
		DepositOrderPaidDetail depositOrderPaidDetail = new DepositOrderPaidDetail();

		depositOrderPaidDetail.setDepositOrderPaidId(pcpsCommonDaoImpl
				.getUniqueIntegerKey());
		depositOrderPaidDetail.setTranTime(tranTime);
		depositOrderPaidDetail.setDepositOrderId(depositOrder
				.getDepositOrderId());
		depositOrderPaidDetail
				.setPaidType(DepositOrderPaidDetail.DEPOSITOPD_PAIDTYPE_CASH);
		depositOrderPaidDetail.setPaidAmount(BigInteger.ZERO
				.subtract(depositOrder.getAlreayPaidAmount()));
		depositOrderPaidDetail.setPayeeAccountId(null);
		depositOrderPaidDetail.setPaidAccountId(null);
		depositOrderPaidDetail.setVoucherNo(null);
		depositOrderPaidDetail.setVoucherRemark(null);
		depositOrderPaidDetail.setVoucherImageId(null);
		depositOrderPaidDetail.setOperId(depositOrder.getOperId());
		depositOrderPaidDetail.setCancelDepositOrderPaidId(null);
		depositOrderPaidDetail.setRemark(depositObject.remark);

		depositOrderPaidDetailDaoImpl
				.insertDepositOrderPaidDetail(depositOrderPaidDetail);

		// 2. 创建充值单状态转换明细
		DepositOrderActionDetail depositOrderActionDetail = new DepositOrderActionDetail();

		depositOrderActionDetail.setDepositOrderId(depositOrder
				.getDepositOrderId());
		depositOrderActionDetail.setActionTime(tranTime);
		depositOrderActionDetail.setOperId(depositObject.operId);
		depositOrderActionDetail
				.setInitialStatus(DepositOrder.DEPORDER_ORDERSTATUS_HAVERECHARGE);
		depositOrderActionDetail
				.setEndStatus(DepositOrder.DEPORDER_ORDERSTATUS_CANCEL);
		depositOrderActionDetail
				.setActionType(DepositOrderActionDetail.DEPOSITOAD_ACTIONTYPE_CANCELDEPOSIT);
		depositOrderActionDetail.setRemark(depositObject.remark);

		depositOrderActionDetailDaoImpl
				.insertDepositOrderActionDetail(depositOrderActionDetail);

		// 3. 充值单置为已取消状态
		depositOrder.setOrderStatus(DepositOrder.DEPORDER_ORDERSTATUS_CANCEL);
		depositOrder.setLastCancelDepositAccSeqNo(depositObject.accSeqNo);
		depositOrder.setAlreayPaidAmount(BigInteger.ZERO);

		depositOrderDaoImpl.updateDepositOrder(depositOrder);
	}

	/**
	 * 单卡销售机构现金充值撤销
	 * 
	 * @param depositObject
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public CashDepositObject CancelCashDeposit(PCPSWebInput webInput,
			CashDepositObject depositObject) throws PCPSApplicationException {

		// 1. 交易检查阶段

		// 入口参数检查
		checkCancelCashDepostArgs(depositObject);

		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(depositObject.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new PCPSApplicationException("", "操作员无效!");

		// 操作员必须是销售机构的操作员
		SaleBranch saleBranch = saleBranchDaoImpl
				.getSaleBranchBySaleBranchNo(sysOpUser.getOperBranchNo());
		if (saleBranch == null)
			throw new PCPSApplicationException("", "非销售机构的操作员!");

		// 操作员对应的发卡商号
		String oper_IssueCompanyNo = PCPSUtil.getICNoByBranchNo(sysOpUser
				.getOperBranchNo());

		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(oper_IssueCompanyNo);

		// 检查充值单
		DepositOrder depositOrder = depositOrderDaoImpl
				.getDepositOrderForUpdate(depositObject.cancelDepositOrderId);
		if (depositOrder == null)
			throw new PCPSApplicationException("", "被撤销充值单"
					+ depositObject.cancelDepositOrderId.toString() + "不存在!");

		// 必须是原充值人撤销
		if (!PCPSUtil.compareObject(depositOrder.getOperId(),
				depositObject.operId))
			throw new PCPSApplicationException("", "不能撤销他人的业务单据!");

		// 必须是单笔充值单
		if (!PCPSUtil.compareObject(depositOrder.getDepositType(),
				DepositOrder.DEPORDER_DEPOSITTYPE_ONE))
			throw new PCPSApplicationException("", "充值单类型不正确,请转其他功能撤销!");

		// 必须是已审核的充值单
		if (!PCPSUtil.compareObject(depositOrder.getOrderStatus(),
				DepositOrder.DEPORDER_ORDERSTATUS_HAVERECHARGE))
			throw new PCPSApplicationException("", "充值单状态非法!");

		// 上次撤销记帐流水号必须为空
		if (!PCPSUtil.isEmpty(depositOrder.getLastCancelDepositAccSeqNo()))
			throw new PCPSApplicationException("", "充值单可能已经被撤销!");

		// 上次记帐流水号和MAC不能为空
		if (PCPSUtil.isEmpty(depositOrder.getLastDepositAccSeqNo())
				|| PCPSUtil.isEmpty(depositOrder.getLastDepositMac()))
			throw new PCPSApplicationException("", "充值单原记帐流水信息异常!");

		// 撤销金额必须一致
		if (!PCPSUtil.compareObject(depositOrder.getTotalDepositAmount(),
				depositObject.amount))
			throw new PCPSApplicationException("", "撤销金额与原充值单不一致!");

		// 检查充值明细
		List<DepositOrderDetail> dodlist = depositOrderDetailDaoImpl
				.getDepositOrderDetailListByDepositOrderId(depositOrder
						.getDepositOrderId());

		if (dodlist == null || dodlist.size() != 1)
			throw new PCPSApplicationException("", "充值单"
					+ depositOrder.getDepositOrderId().toString() + "明细信息异常!");

		// 检查卡信息
		String cardNo = dodlist.get(0).getCardNo();
		ActivateCard ac = activateCardDaoImpl
				.getActivateCardByCardNoForUpdate(cardNo);
		if (ac == null)
			throw new PCPSApplicationException("", "充值单原充值卡号" + cardNo
					+ "信息异常!");

		// 判断销卡状态 -- 不等于未销卡
		if (!PCPSUtil.compareObject(ac.getCloseStatus(),
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡" + cardNo + "已经注销!");

		// 检查余额是否足够
		if (ac.getBalance().compareTo(depositObject.amount) < 0)
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡" + cardNo + "余额不足撤销!");

		// 返回卡号和卡充值撤销前余额
		depositObject.cardNo = ac.getCardNo();
		depositObject.beforeBalance = ac.getBalance();

		// 必须是同一个帐务日期
		AccountSystemTradDetail accountSystemTradDetail = accountSystemTradDetailDaoImpl
				.getAccountSystemTradDetailByAccSeqNo(depositOrder
						.getLastDepositAccSeqNo());
		if (accountSystemTradDetail == null)
			throw new CardTranApplicationException(TuxedoRespCode.RC_NONEXIST,
					"卡" + cardNo + "原充值记帐流水不存在!");

		if (!PCPSUtil.compareObject(accountSystemTradDetail.getTranDate(),
				issueCompany.getTranDate()))
			throw new CardTranApplicationException(TuxedoRespCode.RC_NONEXIST,
					"不能撤销往日的充值业务!");

		// 2. 取消记帐
		Date tranTime = pcpsCommonDaoImpl.getDatabaseSysTime();
		depositObject.accSeqNo = accountBusinessImpl.AccountCancel(issueCompany
				.getIssueCompanyNo(), issueCompany.getTranDate(), tranTime,
				"C_DEPOSIT_" + depositOrder.getDepositOrderId(), depositOrder
						.getLastDepositAccSeqNo(), depositObject.operId,
				"[现金充值撤销]" + depositObject.remark);

		// 3. 取消充值单相关信息
		cancelCashDepositOrder(depositOrder, tranTime, depositObject);

		// 4. 机构信用度&现金记帐
		saleBranch = saleBranchCaptialAccount(saleBranch.getSaleBranchNo(),
				issueCompany.getTranDate(), BigInteger.ZERO, BigInteger.ZERO
						.subtract(depositObject.amount), BigInteger.ZERO
						.subtract(depositObject.amount), BigInteger.ZERO,
				SaleCapitalDetail.TRANTYPE_ACTIVATE, depositOrder
						.getDepositOrderId(), depositObject.operId, tranTime,
				"[现金充值撤销]" + depositObject.remark);

		// 产生现金超限预警提示
		depositObject.cashLimitMessage = saleCashLimitHint(saleBranch,
				issueCompany);

		// 5. 卡余额相关更新
		ac = activateCardDaoImpl.getActivateCardByCardNoForUpdate(ac
				.getCardNo());
		ac.setTotalDeposit(ac.getTotalDeposit().subtract(depositObject.amount));
		activateCardDaoImpl.update(ac);

		// 设置撤销后余额
		depositObject.afterBalance = ac.getBalance();

		return depositObject;
	}

	/**
	 * 获取有效的换发新卡费用
	 * 
	 * @param ac
	 * @param issueCompany
	 * @param cardClassic
	 * @param incObj
	 * @return
	 * @throws PCPSApplicationException
	 */
	// private BigInteger getValidateIssueNewCardFee(ActivateCard ac,
	// IssueCompany issueCompany, CardClassic cardClassic,
	// IssueNewCardObject incObj) throws PCPSApplicationException {
	// if (incObj.paidFee == false)
	// return BigInteger.ZERO;
	//
	// // 本卡种类不收费
	// if (!PCPSUtil.compareObject(cardClassic.getIsCardFee(),
	// CardClassic.CARDCLASSIC_IS_CARDFEE))
	// return BigInteger.ZERO;
	//
	// // 卡种类上定义了收费标准
	// int result = cardClassic.getCardFee().compareTo(BigInteger.ZERO);
	// if (result > 0)
	// return cardClassic.getCardFee();
	//
	// if (result < 0)
	// throw new PCPSApplicationException("", "卡种类["
	// + cardClassic.getCardClassicName() + "]换卡手续费定义有误!");
	//
	// // 取发卡商定义的换卡手续费
	// result = issueCompany.getCardDefaultFee().compareTo(Integer.valueOf(0));
	// if (result < 0)
	// throw new PCPSApplicationException("", "发卡商["
	// + issueCompany.getIssueCompanyName() + "]缺省换卡手续费定义有误!");
	//
	// return BigInteger.valueOf(issueCompany.getCardDefaultFee().intValue());
	// }
	/**
	 * 发新卡出库
	 * 
	 * @param saleBranch
	 *            销售机构号
	 * @param newCardNo
	 *            新卡号
	 * @return
	 * @throws PCPSApplicationException
	 */
	private CardStock issueNewCardOutStock(IssueCompany issueCompany,
			SaleBranch saleBranch, ActivateCard ac, String newCardNo,
			Date tranTime, BigInteger operId, String remark)
			throws PCPSApplicationException {

		// 从库存中检索
		CardStock cs = cardStockDaoImpl
				.getCardStockByCardNoForUpdate(newCardNo);
		if (cs == null)
			throw new PCPSApplicationException("", "新卡号/卡序号[" + newCardNo
					+ "]不存在!");

		// 检索制卡控制表
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(cs.getBatchNo());
		if (mcc == null) {
			throw new PCPSApplicationException("", "新卡号/卡序号[" + newCardNo
					+ "]批次号在制卡控制表中未找到,请检查!");
		}
		// 比较机构是否一致
		if (!PCPSUtil.compareObject(saleBranch.getSaleBranchNo(), cs
				.getSaleBranchNo()))
			throw new PCPSApplicationException("", "新卡号/卡序号[" + newCardNo
					+ "]不在你机构库中,请先调入!");

		// 检查状态
		if (!PCPSUtil.compareObject(cs.getStatus(),
				CardStock.CARDSTOCK_STATUS_NORMAL))
			throw new PCPSApplicationException("", "新卡号/卡序号[" + newCardNo
					+ "]库存状态不正常,请检查!");

		// 从CardStock中删除
		cardStockDaoImpl.removeCardStock(cs);

		// 登记出入库明细
		SaleCardStockDetail saleCardStockDetail = new SaleCardStockDetail();

		saleCardStockDetail.setIoOrderId(pcpsCommonDaoImpl
				.getUniqueIntegerKey());
		saleCardStockDetail.setSaleBranchNo(saleBranch.getSaleBranchNo());
		saleCardStockDetail.setTranDate(issueCompany.getTranDate());
		saleCardStockDetail.setTrantime(tranTime);
		// 补换发出库
		saleCardStockDetail
				.setTranType(SaleCardStockDetail.SALECARD_TRANTYPE_REISSUEOUT);
		saleCardStockDetail.setCardFaceId(mcc.getCardFaceId());
		// saleCardStockDetail.setCardClassicId(mcc.getCardClassicId());
		// saleCardStockDetail.setCardParValueId(mcc.getCardParValueId());
		saleCardStockDetail.setBatchNo(cs.getBatchNo());
		saleCardStockDetail.setCardStartSeqNo(cs.getCardSeqNo());
		saleCardStockDetail.setCardEndSeqNo(cs.getCardSeqNo());
		saleCardStockDetail.setOrderCount(Integer.valueOf(1));
		saleCardStockDetail.setOperId(operId);
		saleCardStockDetail.setRemark(remark);

		saleCardStockDetailDaoImpl.insert(saleCardStockDetail);

		return cs;
	}

	/**
	 * 产生新卡
	 * 
	 * @param oldac
	 * @param cs
	 * @return
	 */
	private ActivateCard makeNewActivateCard(ActivateCard oldac, CardStock cs)
			throws PCPSApplicationException {
		ActivateCard ac = new ActivateCard();

		ac.setBatchNo(cs.getBatchNo());
		ac.setCardSeqNo(cs.getCardSeqNo());
		ac.setCardNo(cs.getCardNo());
		ac.setCardClassicId(oldac.getCardClassicId());
		ac.setMasterAccNo(oldac.getMasterAccNo());
		ac.setCardPwd(cs.getCardPwd());
		ac.setTwoTrackContent(cs.getTwoTrackContent());
		ac.setThirdTrackContent(cs.getThirdTrackContent());
		ac.setSaleBranchNo(oldac.getSaleBranchNo());
		ac.setSaleOrderId(oldac.getSaleOrderId());
		ac.setBuyerId(oldac.getBuyerId());
		ac.setOwnerId(oldac.getOwnerId());
		ac.setInitialBalance(oldac.getInitialBalance());
		ac.setTotalDeposit(oldac.getTotalDeposit());
		ac.setBalance(oldac.getBalance());
		ac.setExpired(oldac.getExpired());
		ac.setLastExpiredFeeDate(oldac.getLastExpiredFeeDate());
		ac.setPwdErrCnt(Integer.valueOf(0));
		ac.setLastPwdErrTime(null);
		ac.setOpenTime(oldac.getOpenTime());
		ac.setOpenStatus(ActivateCard.ACTIVATECARD_OPENSTATUS_ISSUE_NEW);
		ac.setCloseStatus(ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL);
		ac.setLastLossTime(null);
		ac.setLossStatus(ActivateCard.ACTIVATECARD_LOSSSTATUS_NORMAL);
		ac.setManualLockStatus(oldac.getManualLockStatus());
		ac.setActivateMac(null);
		ac.setTotalConsumeCount(oldac.getTotalConsumeCount());
		ac.setOrigCardNo(oldac.getCardNo());
		ac.setNewCardNo(null);
		ac.setOpenBranchNo(oldac.getOpenBranchNo());
		ac.setCardFaceId(oldac.getCardFaceId());
		ac.setWalletAccNo(oldac.getWalletAccNo());
		ac.setWalletBalance(oldac.getWalletBalance());

		return ac;
	}

	/**
	 * 挂失换发/补发新卡交易入口参数检查
	 * 
	 * @param incObj
	 * @throws PCPSApplicationException
	 */
	private void checkIssueNewCardArgs(IssueNewCardObject incObj)
			throws PCPSApplicationException {

		if (incObj == null)
			throw new PCPSApplicationException("", "入口参数为空!");

		// 原卡号
		if (PCPSUtil.isEmpty(incObj.cardNo))
			throw new PCPSApplicationException("", "原卡号为空!");

		// 主账户是否有充值待审或赎回待审资金
		MasterAccount mac = masterAccountDaoImpl
				.getMasterAccountByCardNo(incObj.cardNo);
		if (mac.getAuthDeposit().compareTo(BigInteger.ZERO) > 0) {
			throw new PCPSApplicationException("", "卡内有充值待审资金,金额为"
					+ mac.getAuthDeposit().doubleValue() / 100 + ",不能换卡!");
		}
		if (mac.getAuthRedemp().compareTo(BigInteger.ZERO) > 0) {
			throw new PCPSApplicationException("", "卡内有赎回待审资金,金额为"
					+ mac.getAuthRedemp().doubleValue() / 100 + ",不能换卡!");
		}
		// 新卡号
		if (PCPSUtil.isEmpty(incObj.newCardNo))
			throw new PCPSApplicationException("", "新卡号为空!");

		// 操作员
		if (incObj.operId == null)
			throw new PCPSApplicationException("", "操作员为空!");

		// 备注
		if (!incObj.isTrail && PCPSUtil.isEmpty(incObj.remark))
			throw new PCPSApplicationException("", "备注不能为空!");
	}

	/**
	 * 挂失补发新卡
	 * 
	 * @param eeObj
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public IssueNewCardObject LossReIssueNewCard(PCPSWebInput webInput,
			IssueNewCardObject incObj) throws PCPSApplicationException {
		// 1. 交易检查阶段

		// 入口参数检查
		checkIssueNewCardArgs(incObj);

		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(incObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new PCPSApplicationException("", "操作员无效!");

		// 检查销售机构日终状态
		SaleBranch saleBranch = checkSaleBranchDayOff(webInput
				.getOperBranchNo());

		// 操作员对应的发卡商号
		String oper_IssueCompanyNo = PCPSUtil.getICNoByBranchNo(sysOpUser
				.getOperBranchNo());

		// 检索卡信息
		ActivateCard oldac = activateCardDaoImpl
				.getActivateCardByCardNoForUpdate(incObj.cardNo);
		if (oldac == null)
			throw new PCPSApplicationException("", "卡号" + incObj.cardNo + "无效!");

		// 检索制卡控制批次
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(oldac.getBatchNo());

		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(mcc.getIssueCompanyNo());

		// 操作员与卡的归属必须是同一发卡商
		if (!PCPSUtil.compareObject(oper_IssueCompanyNo, mcc
				.getIssueCompanyNo()))
			throw new PCPSApplicationException("", "卡不存在!");

		// 判断销卡状态 -- 不等于未销卡
		if (!PCPSUtil.compareObject(oldac.getCloseStatus(),
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡" + oldac.getCardNo() + "已经注销!");

		// 必须是正式挂失状态
		if (!PCPSUtil.compareObject(oldac.getLossStatus(),
				ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED))
			throw new PCPSApplicationException("", "卡状态必须为正式挂失!");

		// 上次挂失时间
		if (oldac.getLastLossTime() == null)
			throw new PCPSApplicationException("", "卡本次挂失时间异常!");

		// 当前时间
		Date tranTime = pcpsCommonDaoImpl.getDatabaseSysTime();

		int result = issueCompany.getLossLimit().compareTo(Integer.valueOf(0));
		if (result < 0)
			throw new PCPSApplicationException("", "发卡商["
					+ issueCompany.getIssueCompanyName() + "]挂失补发时限设置有误!");

		if (result > 0) {
			// 挂失补发时限必须够
			java.util.Calendar cal = java.util.Calendar.getInstance();
			cal.setTime(PCPSUtil.getZeroedHMS(oldac.getLastLossTime()));
			cal.add(java.util.Calendar.DAY_OF_MONTH, issueCompany
					.getLossLimit());
			java.util.Date unlockTime = cal.getTime();
			Date e_tranTime = PCPSUtil.getZeroedHMS(tranTime);
			if (unlockTime.compareTo(e_tranTime) >= 0)
				throw new PCPSApplicationException("", "挂失补发时限"
						+ PCPSUtil.getStringYMDByDate(unlockTime) + "未到!");
		}

		// 挂失补发手续费
		// 挂失交易始终要扣费
		incObj.paidFee = true;

		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_changeLossCard, oldac
						.getCardNo(), null, issueCompany.getTranDate(), oldac
						.getBalance());

		BigInteger fee = ifp.getFee();

		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_changeLossCard);

		// 返回的手续费
		incObj.fee = fee;

		// 如果是试算,把试算结果返回
		if (incObj.isTrail) {
			return incObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !incObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}
		// 检查收费模式
		if (!PCPSUtil.compareObject(incObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(incObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");

		// 检查优惠的手续费
		if ((incObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(incObj.discountFee) > 0
				|| incObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (incObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(incObj.authOperId, incObj.authPwd, incObj.operId,
					sysOpUser.getOperBranchNo());
		else
			incObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(incObj.discountFee);

		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(incObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			incObj.cashFee = BigInteger.ZERO;
			incObj.cardFee = factfee;
		} else {
			incObj.cashFee = factfee;
			incObj.cardFee = BigInteger.ZERO;
		}

		String remark = "[挂失补发新卡]" + incObj.remark;

		// 2. 新卡出库
		CardStock cs = issueNewCardOutStock(issueCompany, saleBranch, oldac,
				incObj.newCardNo, tranTime, incObj.operId, remark);

		// 4. 老卡更新
		ActivateCard newAc = makeNewActivateCard(oldac, cs);

		BigInteger masaccno = oldac.getMasterAccNo();
		incObj.beforeBalance = oldac.getBalance();
		incObj.afterBalance = oldac.getBalance();

		oldac.setBalance(BigInteger.ZERO);
		oldac.setNewCardNo(cs.getCardNo());
		oldac
				.setCloseStatus(ActivateCard.ACTIVATECARD_CLOSESTATUS_CLOSED_ISSUE_NEW);
		activateCardDaoImpl.update(oldac);
		// 置空主帐号
		activateCardDaoImpl.clearMasterAccNo(oldac.getCardNo());

		// 5. 创建新卡
		activateCardDaoImpl.insert(newAc);

		// 6. 更新主帐户的卡号
		MasterAccount macc = masterAccountDaoImpl
				.getMasterAccountByMasterAccNoForUpdate(masaccno);
		macc.setCardNo(cs.getCardNo());
		masterAccountDaoImpl.update(macc);

		// 事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		String accSeqNo = null;

		// 卡扣手续费
		if (incObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = incObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = newAc.getCardNo();
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = incObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "挂失补发手续费");

			// 保留流水号
			accSeqNo = paidResult.accseqno;

			// 设置返回余额
			incObj.afterBalance = paidResult.cardbalance.get(newAc.getCardNo());
		}

		// 现金收入记帐
		if (incObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					incObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid,
					incObj.operId, tranTime, "挂失补发手续费");

		String cardEventOrderSeq = pcpsCommonDaoImpl.getOrderNumber(tranTime,
				sysOpUser.getOperBranchNo());
		incObj.orderSeqNo = evid.toString();// 返回的CardEventId

		// 7. 记载换卡事件
		// 记载换卡事件日志
		CardEventLog cel = new CardEventLog();
		cel.setBalance(incObj.beforeBalance);
		cel.setFee(fee);
		cel.setCardFee(incObj.cardFee);
		cel.setCashFee(incObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(incObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(incObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(incObj.operId);
		cel.setRemark(remark);
		cel.setCardEventId(evid);// 主键
		cel.setCardEventOrderSeq(cardEventOrderSeq);// 单号
		cel.setCardNo(oldac.getCardNo());
		cel.setCardClassicId(oldac.getCardClassicId());
		cel.setExpired(oldac.getExpired());
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(tranTime);
		cel.setMasterAccNo(masaccno);
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setNewCardNo(cs.getCardNo());
		cel.setNewClassicId(newAc.getCardClassicId());
		cel.setNewExpired(newAc.getExpired());
		// 挂失换卡
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_LOSSED);
		cardEventLogDaoImpl.insert(cel);

		return incObj;
	}

	/**
	 * 换发新卡
	 * 
	 * @param eeObj
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public IssueNewCardObject ReIssueNewCard(PCPSWebInput webInput,
			IssueNewCardObject incObj) throws PCPSApplicationException {
		// 1. 交易检查阶段
		// 入口参数检查
		checkIssueNewCardArgs(incObj);

		// 原密码
		if (PCPSUtil.isEmpty(incObj.pwd))
			throw new PCPSApplicationException("", "原密码为空!");

		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(incObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new PCPSApplicationException("", "操作员无效!");

		// 检查销售机构日终状态
		SaleBranch saleBranch = checkSaleBranchDayOff(webInput
				.getOperBranchNo());

		// 操作员对应的发卡商号
		String oper_IssueCompanyNo = PCPSUtil.getICNoByBranchNo(sysOpUser
				.getOperBranchNo());

		// 检索卡信息
		ActivateCard oldac = activateCardDaoImpl
				.getActivateCardByCardNo(incObj.cardNo);
		if (oldac == null)
			throw new PCPSApplicationException("", "卡号" + incObj.cardNo + "无效!");

		// 检索制卡控制批次
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(oldac.getBatchNo());

		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(mcc.getIssueCompanyNo());

		// 操作员与卡的归属必须是同一发卡商
		if (!PCPSUtil.compareObject(oper_IssueCompanyNo, mcc
				.getIssueCompanyNo()))
			throw new PCPSApplicationException("", "卡不存在!");

		// 检查密码
		oldac = chkCardAttribute(incObj.cardNo, incObj.pwd, null);

		// 检查卡状态能否交易
		isCardCanDoTrans(oldac);

		// 当前时间
		Date tranTime = pcpsCommonDaoImpl.getDatabaseSysTime();

		// 补发手续费
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_changeNewCard, oldac
						.getCardNo(), null, issueCompany.getTranDate(), oldac
						.getBalance());

		BigInteger fee = ifp.getFee();

		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_changeNewCard);

		// 返回的手续费
		incObj.fee = fee;
		incObj.beforeBalance = oldac.getBalance();

		// 如果是试算,把试算结果返回
		if (incObj.isTrail) {
			return incObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !incObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}

		// 检查收费模式
		if (!PCPSUtil.compareObject(incObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(incObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");

		// 检查优惠的手续费
		if ((incObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(incObj.discountFee) > 0
				|| incObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (incObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(incObj.authOperId, incObj.authPwd, incObj.operId,
					sysOpUser.getOperBranchNo());
		else
			incObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(incObj.discountFee);

		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(incObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			incObj.cashFee = BigInteger.ZERO;
			incObj.cardFee = factfee;
		} else {
			incObj.cashFee = factfee;
			incObj.cardFee = BigInteger.ZERO;
		}

		String remark = "[换发新卡]" + incObj.remark;
		// 2. 新卡出库
		CardStock cs = issueNewCardOutStock(issueCompany, saleBranch, oldac,
				incObj.newCardNo, tranTime, incObj.operId, remark);

		// 4. 老卡更新
		ActivateCard newAc = makeNewActivateCard(oldac, cs);
		BigInteger masaccno = oldac.getMasterAccNo();
		incObj.beforeBalance = oldac.getBalance();
		incObj.afterBalance = oldac.getBalance();
		oldac.setBalance(BigInteger.ZERO);
		oldac.setNewCardNo(cs.getCardNo());
		oldac
				.setCloseStatus(ActivateCard.ACTIVATECARD_CLOSESTATUS_CLOSED_ISSUE_NEW);
		activateCardDaoImpl.update(oldac);
		// 置空主帐号
		activateCardDaoImpl.clearMasterAccNo(oldac.getCardNo());
		// 5. 创建新卡
		activateCardDaoImpl.insert(newAc);
		// 6. 更新主帐户的卡号
		MasterAccount macc = masterAccountDaoImpl
				.getMasterAccountByMasterAccNoForUpdate(masaccno);
		macc.setCardNo(cs.getCardNo());
		masterAccountDaoImpl.update(macc);

		// 事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		String accSeqNo = null;

		// 手续费
		if (incObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = incObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = newAc.getCardNo();
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = incObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;
			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "换发新卡手续费");
			// 保留流水号
			accSeqNo = paidResult.accseqno;
			// 设置返回余额
			incObj.afterBalance = paidResult.cardbalance.get(newAc.getCardNo());
		}

		// 现金收入记帐
		if (incObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					incObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid,
					incObj.operId, tranTime, "换发新卡手续费");

		String cardEventOrderSeq = pcpsCommonDaoImpl.getOrderNumber(tranTime,
				sysOpUser.getOperBranchNo());
		incObj.orderSeqNo = evid.toString();// 返回的CardEventId

		// 7. 记载换卡事件
		// 记载换卡事件日志
		CardEventLog cel = new CardEventLog();

		cel.setBalance(incObj.beforeBalance);
		cel.setFee(fee);
		cel.setCardFee(incObj.cardFee);
		cel.setCashFee(incObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(incObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(incObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(incObj.operId);
		cel.setRemark(remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(oldac.getCardNo());
		cel.setCardClassicId(oldac.getCardClassicId());
		cel.setExpired(oldac.getExpired());
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(tranTime);
		cel.setMasterAccNo(masaccno);
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setNewCardNo(cs.getCardNo());
		cel.setNewClassicId(newAc.getCardClassicId());
		cel.setNewExpired(newAc.getExpired());
		// 换发新卡
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_CHANGE_CARD);

		cardEventLogDaoImpl.insert(cel);

		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Add, "换发新卡", "CardNo: " + cel.getCardNo());

		return incObj;
	}

	/**
	 * 变更卡种类交易入口参数检查
	 * 
	 * @param cccObj
	 * @throws PCPSApplicationException
	 */
	private void checkChangeCardClassicArgs(ChangeCardClassicObject cccObj)
			throws PCPSApplicationException {

		if (cccObj == null)
			throw new PCPSApplicationException("", "入口参数为空!");

		// 卡号
		if (PCPSUtil.isEmpty(cccObj.cardNo))
			throw new PCPSApplicationException("", "卡号为空!");

		// 密码
		if (PCPSUtil.isEmpty(cccObj.pwd))
			throw new PCPSApplicationException("", "密码为空!");

		// 新卡种类
		if (cccObj.newCardClassicId == null)
			throw new PCPSApplicationException("", "新卡种类为空!");

		// 操作员
		if (cccObj.operId == null)
			throw new PCPSApplicationException("", "操作员为空!");

		// 非试算时必须输入备注
		if (!cccObj.isTrial && PCPSUtil.isEmpty(cccObj.remark))
			throw new PCPSApplicationException("", "备注为空!");
	}

	/**
	 * 检查变更种类的兼容性
	 * 
	 * @param oldCardClassic
	 * @param newCardClassicId
	 * @param paidFee
	 * @return
	 * @throws PCPSApplicationException
	 */
	private void checkChangeCardClassic(CardClassic oldCardClassic,
			BigInteger newCardClassicId) throws PCPSApplicationException {

		// 变更种类不能相同
		if (oldCardClassic.getCardClassicId().equals(newCardClassicId))
			throw new PCPSApplicationException("", "必须是不同卡种类的转换!");

		// 取新卡种类
		CardClassic newCardClassic = cardClassicDaoImpl
				.getCardClassicByCardClassicId(newCardClassicId);

		// 新卡种类必须存在且同属一家发卡商
		if (newCardClassic == null
				|| !PCPSUtil.compareObject(oldCardClassic.getIssueCompanyNo(),
						newCardClassic.getIssueCompanyNo()))
			throw new PCPSApplicationException("", "新卡种类不存在或无效!");

		// 新卡种类必须与原卡种类介质类型一致
		// if (!PCPSUtil.compareObject(oldCardClassic.getMediaType(),
		// newCardClassic.getMediaType()))
		// throw new PCPSApplicationException("", "新旧卡种类介质类型必须一致!");
	}

	/**
	 * 变更卡种类
	 * 
	 * @param eeObj
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public ChangeCardClassicObject ChangeCardClassic(PCPSWebInput webInput,
			ChangeCardClassicObject cccObj) throws PCPSApplicationException {
		// 1. 交易检查阶段

		// 入口参数检查
		checkChangeCardClassicArgs(cccObj);

		// 检查销售机构日终状态
		checkSaleBranchDayOff(webInput.getOperBranchNo());

		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(cccObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new PCPSApplicationException("", "操作员无效!");

		// 操作员对应的发卡商号
		String oper_IssueCompanyNo = PCPSUtil.getICNoByBranchNo(sysOpUser
				.getOperBranchNo());

		// 检索卡信息
		ActivateCard ac = activateCardDaoImpl
				.getActivateCardByCardNo(cccObj.cardNo);
		if (ac == null)
			throw new PCPSApplicationException("", "卡号" + cccObj.cardNo + "无效!");

		// 检索制卡控制批次
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(ac.getBatchNo());

		// 取卡种类
		CardClassic cardClassic = cardClassicDaoImpl
				.getCardClassicByCardClassicId(ac.getCardClassicId());

		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(mcc.getIssueCompanyNo());

		// 操作员与卡的归属必须是同一发卡商
		if (!PCPSUtil.compareObject(oper_IssueCompanyNo, mcc
				.getIssueCompanyNo()))
			throw new PCPSApplicationException("", "卡不存在!");

		// 检查变更的兼容性
		checkChangeCardClassic(cardClassic, cccObj.newCardClassicId);

		// 检查密码
		ac = chkCardAttribute(cccObj.cardNo, cccObj.pwd, null);

		// 检查卡状态能否交易
		isCardCanDoTrans(ac);

		// 当前时间
		Date tranTime = pcpsCommonDaoImpl.getDatabaseSysTime();

		// 变更手续费
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_changeClassic, ac.getCardNo(),
				cccObj.newCardClassicId, issueCompany.getTranDate(), ac
						.getBalance());

		BigInteger fee = ifp.getFee();

		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_changeClassic);

		// 如果是试算,则返回变更手续费
		cccObj.fee = fee;

		if (cccObj.isTrial) {
			return cccObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !cccObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}

		// 检查收费模式
		if (!PCPSUtil.compareObject(cccObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(cccObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");

		// 检查优惠的手续费
		if ((cccObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(cccObj.discountFee) > 0
				|| cccObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (cccObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(cccObj.authOperId, cccObj.authPwd, cccObj.operId,
					sysOpUser.getOperBranchNo());
		else
			cccObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(cccObj.discountFee);

		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(cccObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			cccObj.cashFee = BigInteger.ZERO;
			cccObj.cardFee = factfee;
		} else {
			cccObj.cashFee = factfee;
			cccObj.cardFee = BigInteger.ZERO;
		}

		String remark = "[卡种类变更]" + cccObj.remark;

		// 2. 变更新卡种类
		cccObj.beforeBalance = ac.getBalance();
		cccObj.afterBalance = ac.getBalance();
		ac.setCardClassicId(cccObj.newCardClassicId);
		activateCardDaoImpl.update(ac);

		// 事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		String accSeqNo = null;

		// 手续费
		if (cccObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = cccObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = ac.getCardNo();
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = cccObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "变更卡种类手续费");

			// 保留流水号
			accSeqNo = paidResult.accseqno;

			// 设置返回余额
			cccObj.afterBalance = paidResult.cardbalance.get(ac.getCardNo());
		}

		// 现金收入记帐
		if (cccObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					cccObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid,
					cccObj.operId, tranTime, "变更卡种类手续费");

		String cardEventOrderSeq = pcpsCommonDaoImpl.getOrderNumber(tranTime,
				sysOpUser.getOperBranchNo());
		cccObj.orderSeqNo = evid.toString();// 返回的CardEventId
		cccObj.isTrial = false;
		// 3. 记载换卡事件
		// 记载换卡事件日志
		CardEventLog cel = new CardEventLog();

		cel.setBalance(cccObj.beforeBalance);
		cel.setFee(fee);
		cel.setCardFee(cccObj.cardFee);
		cel.setCashFee(cccObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(cccObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(cccObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(cccObj.operId);
		cel.setRemark(remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(ac.getCardNo());
		cel.setCardClassicId(cardClassic.getCardClassicId());
		cel.setExpired(ac.getExpired());
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(tranTime);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setNewClassicId(ac.getCardClassicId());
		// 变更卡种类
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_CHANGE_TYPE);

		cardEventLogDaoImpl.insert(cel);

		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Add, "变更卡种类", "CardNo: " + ac.getCardNo());

		return cccObj;
	}

	/**
	 * 获取卡交易最大可扣除资金
	 * 
	 * @param webInput
	 * @param issueCompany
	 * @param ifp
	 * @param cardNo
	 * @return
	 */
	private BigInteger getMaxDeductAmountFromCard(PCPSWebInput webInput,
			IssueCompany issueCompany, IssueFeePolicy ifp, ActivateCard card)
			throws PCPSApplicationException {
		// 登录信息
		if (webInput == null || PCPSUtil.isEmpty(webInput.getOperBranchNo()))
			throw new PCPSApplicationException("", "登录信息为空!");

		// 卡号
		if (card == null || PCPSUtil.isEmpty(card.getCardNo()))
			throw new PCPSApplicationException("", "卡号为空!");

		// 操作员
		if (webInput.getOperId() == null)
			throw new PCPSApplicationException("", "操作员为空!");

		// 最大冻结金额
		BigInteger deduct = BigInteger.ZERO;
		// 手续费
		BigInteger fee = BigInteger.ZERO;

		// 如果是收现金,则最大冻结金额为余额
		if (PCPSUtil.compareObject(ifp.getAmountType(),
				IssueFeePolicy.IFPolicy_amountType_Cash)) {
			deduct = card.getBalance();
			return deduct;
		}

		// 如果是固定金额
		if (PCPSUtil.compareObject(ifp.getFeeType(),
				IssueFeePolicy.IFPolicy_FeeType_Fix)) {
			fee = ifp.getFee();
			if (BigInteger.ZERO.compareTo(fee) > 0)
				throw new PCPSApplicationException("", "手续费计算错!");
			// 取发卡商资费上下限
			fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
					IssueFeePolicy.IFPolicy_busiType_freeze);
			deduct = card.getBalance().subtract(fee);
			return deduct;
		}

		// 如果是按比率收取手续费,则循环算最大可冻结资金
		if (PCPSUtil.compareObject(ifp.getFeeType(),
				IssueFeePolicy.IFPolicy_FeeType_Ratio)) {
			deduct = card.getBalance().subtract(fee);
			return deduct;
		}
		return deduct;
	}

	public static void main(String[] args) {
		// 费率万分之10
		BigInteger fixRatio = BigInteger.TEN;
		// 余额10000分
		BigInteger amount = new BigInteger("10000");
		// 最大冻结金额
		BigInteger deduce = BigInteger.ZERO;
		deduce = amount.divide((new BigInteger("10000").add(fixRatio)));
		System.out.println(deduce.toString());
	}

	/**
	 * 冻结入口参数检查
	 * 
	 * @param faObj
	 * @throws PCPSApplicationException
	 */
	private void checkFreezeArgs(FreezeAccountObject faObj)
			throws PCPSApplicationException {

		if (faObj == null)
			throw new PCPSApplicationException("", "入口参数为空!");

		// 卡号
		if (PCPSUtil.isEmpty(faObj.cardNo))
			throw new PCPSApplicationException("", "卡号为空!");

		// 操作员
		if (faObj.operId == null)
			throw new PCPSApplicationException("", "操作员为空!");

		// 备注
		if (PCPSUtil.isEmpty(faObj.remark))
			throw new PCPSApplicationException("", "备注为空!");
	}

	/**
	 * 冻结
	 * 
	 * @param faObj
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public FreezeAccountObject FreezeAccount(PCPSWebInput webInput,
			FreezeAccountObject faObj) throws PCPSApplicationException {
		// 1. 交易检查阶段
		// 入口参数检查
		checkFreezeArgs(faObj);
		// 检查销售机构日终状态
		checkSaleBranchDayOff(webInput.getOperBranchNo());

		// 检查冻结金额
		if (faObj.amount == null
				|| faObj.amount.compareTo(BigInteger.ZERO) <= 0)
			throw new PCPSApplicationException("", "冻结金额非法!");

		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(faObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new PCPSApplicationException("", "操作员无效!");

		// 操作员对应的发卡商号
		String oper_IssueCompanyNo = PCPSUtil.getICNoByBranchNo(sysOpUser
				.getOperBranchNo());

		// 检索卡信息
		ActivateCard ac = activateCardDaoImpl
				.getActivateCardByCardNo(faObj.cardNo);
		if (ac == null)
			throw new PCPSApplicationException("", "卡号" + faObj.cardNo + "无效!");

		// 检索制卡控制批次
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(ac.getBatchNo());

		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(mcc.getIssueCompanyNo());

		// 操作员与卡的归属必须是同一发卡商
		if (!PCPSUtil.compareObject(oper_IssueCompanyNo, issueCompany
				.getIssueCompanyNo()))
			throw new PCPSApplicationException("", "卡不存在!");

		// 判断销卡状态 -- 不等于未销卡
		if (!PCPSUtil.compareObject(ac.getCloseStatus(),
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡" + ac.getCardNo() + "已经注销!");

		// 2. 请求帐户子系统冻结服务
		Map<BigInteger, BigInteger> masAccNoMap = new HashMap<BigInteger, BigInteger>();
		masAccNoMap.put(ac.getMasterAccNo(), faObj.amount);

		// 冻结金额
		MasterAccount ma = masterAccountDaoImpl
				.getMasterAccountByMasterAccNo(ac.getMasterAccNo());
		if (faObj.amount.compareTo(ac.getBalance().subtract(
				ma.getFreezeAmount())) > 0) {
			throw new PCPSApplicationException("", "卡号:"
					+ faObj.cardNo
					+ ",冻结金额:"
					+ faObj.amount.doubleValue()
					/ 100
					+ ",超过最大冻结金额:"
					+ ac.getBalance().subtract(ma.getFreezeAmount())
							.doubleValue() / 100);
		}

		// 手续费扣除
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_freeze, ac.getCardNo(), null,
				issueCompany.getTranDate(), ac.getBalance());
		BigInteger fee = ifp.getFee();
		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_freeze);
		faObj.fee = fee;
		// 如果是试算,把试算结果返回
		if (faObj.isTrail) {
			return faObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !faObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}
		// 检查收费模式
		if (!PCPSUtil.compareObject(faObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(faObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");
		// 检查优惠的手续费
		if ((faObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(faObj.discountFee) > 0
				|| faObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (faObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(faObj.authOperId, faObj.authPwd, faObj.operId,
					sysOpUser.getOperBranchNo());
		else
			faObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(faObj.discountFee);
		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(faObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			if (faObj.amount.add(factfee).compareTo(
					ac.getBalance().subtract(ma.getFreezeAmount())) > 0) {
				throw new PCPSApplicationException("", "卡"
						+ ac.getCardSeqNo()
						+ "的冻结资金("
						+ faObj.amount.doubleValue()
						/ 100
						+ "),卡内扣手续费("
						+ factfee.doubleValue()
						/ 100
						+ "),已超出卡内可冻结余额:"
						+ ac.getBalance().subtract(ma.getFreezeAmount())
								.doubleValue() / 100 + "!");
			}
			faObj.cashFee = BigInteger.ZERO;
			faObj.cardFee = factfee;
		} else {
			faObj.cashFee = factfee;
			faObj.cardFee = BigInteger.ZERO;
		}

		accountBusinessImpl.FreezeAccount(issueCompany.getIssueCompanyNo(),
				faObj.operId, "[冻结]" + faObj.remark, masAccNoMap, false);

		// 卡事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		Date occurTime = pcpsCommonDaoImpl.getDatabaseSysTime();
		String accSeqNo = null;
		// 如果需要延期,则执行扣费动作
		if (faObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = faObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = faObj.cardNo;
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = faObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "卡冻结手续费");
			// 保留流水号
			accSeqNo = paidResult.accseqno;
			// 设置返回余额
			faObj.balance = paidResult.cardbalance.get(faObj.cardNo);
		}

		// 现金收入记帐
		if (faObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					faObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid, faObj.operId,
					occurTime, "卡冻结手续费");

		// 业务单号
		String cardEventOrderSeq = pcpsCommonDaoImpl.getOrderNumber(occurTime,
				webInput.getOperBranchNo());
		faObj.orderSeqNo = evid.toString();// 返回的CardEventId

		// 4.记载卡事件日志
		CardEventLog cel = new CardEventLog();
		cel.setBalance(faObj.balance);
		cel.setFee(fee);
		cel.setCardFee(faObj.cardFee);
		cel.setCashFee(faObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(faObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(faObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(faObj.operId);
		cel.setRemark(faObj.remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(ac.getCardNo());
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setExpired(ac.getExpired());
		cel.setNewExpired(null);
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(occurTime);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_FREEZE);
		cardEventLogDaoImpl.insert(cel);
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Edit, "卡冻结", "CardNo:" + cel.getCardNo());

		return faObj;
	}

	/**
	 * 批量卡冻结
	 * 
	 * @param eeObj
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public FreezeAccountObject batchFreezeAccount(PCPSWebInput input,
			FreezeAccountObject faObj) throws PCPSApplicationException {
		// 1. 交易检查阶段
		if (input == null || PCPSUtil.isEmpty(input.getOperBranchNo())
				|| input.getOperId() == null) {
			throw new CardTranApplicationException("", "", "登录用户必输参数为空!");
		}
		if (PCPSUtil.isEmpty(faObj.startCardSeqNo)
				|| PCPSUtil.isEmpty(faObj.endCardSeqNo)) {
			throw new CardTranApplicationException("", "", "起始顺序号或者终止顺序号为空!");
		}
		if (faObj.count.intValue() < 1) {
			throw new CardTranApplicationException("", "", "卡张数不可小于1张卡!");
		}

		if (PCPSUtil.isEmpty(faObj.remark)) {
			throw new CardTranApplicationException("", "", "备注为空!");
		}
		String batchNo = "";
		if (faObj.startCardSeqNo.trim().length() < 18) {
			if (!faObj.startCardSeqNo.substring(0, 6).equals(
					faObj.endCardSeqNo.substring(0, 6))) {
				throw new CardTranApplicationException("", "",
						"起始终止卡序号不在同一批次中!");
			}
			batchNo = PCPSUtil.getIssueCompanyNo(input)
					+ faObj.startCardSeqNo.substring(0, 6);
		} else {
			if (!faObj.startCardSeqNo.substring(0, 12).equals(
					faObj.endCardSeqNo.substring(0, 12))) {
				throw new CardTranApplicationException("", "",
						"起始终止卡序号不在同一批次中!");
			}
			batchNo = faObj.startCardSeqNo.substring(0, 12);
		}

		String start = "";
		if (faObj.startCardSeqNo.trim().length() < 18) {
			start = faObj.startCardSeqNo.substring(6, 12);
			String end = faObj.endCardSeqNo.substring(6, 12);
			int selCount = Integer.parseInt(end) - Integer.parseInt(start) + 1;
			if (faObj.count.intValue() != selCount) {
				throw new CardTranApplicationException("", "", "冻结卡顺序号不连续!");
			}
		} else {
			start = faObj.startCardSeqNo.substring(12, 18);
			String end = faObj.endCardSeqNo.substring(12, 18);
			int selCount = Integer.parseInt(end) - Integer.parseInt(start) + 1;
			if (faObj.count.intValue() != selCount) {
				throw new CardTranApplicationException("", "", "冻结卡顺序号不连续!");
			}
		}
		String cardSeqNo = "";
		Integer start_i = Integer.parseInt(start);
		Integer end_i = start_i + faObj.count;
		ActivateCard ac = null;
		FreezeAccountObject obj = null;
		BigInteger totalFee = BigInteger.ZERO;
		// 2.新系统卡序号
		if (faObj.startCardSeqNo.trim().length() == 18) {
			for (int i = start_i; i < end_i; i++) {
				obj = new FreezeAccountObject();
				cardSeqNo = batchNo + String.format("%06d", i);
				ac = activateCardDaoImpl.getActivateCardByCardSeqNo(cardSeqNo);
				if (ac == null) {
					throw new CardTranApplicationException("", "",
							"激活卡列表中不存在顺序号为“" + cardSeqNo + "”卡!");
				}
				obj.amount = ac.getBalance();
				obj.operId = input.getOperId();
				obj.cardNo = ac.getCardNo();
				obj.remark = faObj.remark;
				obj.isTrail = faObj.isTrail;
				obj.chargeMode = faObj.chargeMode;
				obj = FreezeAccount(input, obj);
				totalFee = totalFee.add(obj.fee);
			}
		}
		// 3.旧系统卡序号
		else {
			String br = faObj.startCardSeqNo.substring(0, 6);
			Integer start_b = Integer.parseInt(faObj.startCardSeqNo.substring(
					6, 12));
			Integer end_b = Integer.parseInt(faObj.endCardSeqNo
					.substring(6, 12));
			for (int i = start_b; i < end_b; i++) {
				obj = new FreezeAccountObject();
				cardSeqNo = br + String.format("%06d", i);
				ac = activateCardDaoImpl.getActivateCardByCardSeqNo(cardSeqNo);
				if (ac == null) {
					throw new CardTranApplicationException("", "",
							"激活卡列表中不存原始系统中顺序号为“" + cardSeqNo + "”卡!");
				}
				obj.amount = ac.getBalance();
				obj.operId = input.getOperId();
				obj.cardNo = ac.getCardNo();
				obj.remark = faObj.remark;
				obj.isTrail = faObj.isTrail;
				obj.chargeMode = faObj.chargeMode;
				obj = FreezeAccount(input, obj);
				totalFee = totalFee.add(obj.fee);
			}
		}
		// 如果是试算,把试算结果返回
		if (faObj.isTrail) {
			faObj.fee = totalFee;
			return faObj;
		}
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(input, SysOperLog.operType_Edit,
				"批量卡冻结", "startCardSeqNo: " + faObj.startCardSeqNo
						+ "endCardSeqNo" + faObj.endCardSeqNo);
		return faObj;
	}

	/**
	 * 解冻结
	 * 
	 * @param faObj
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public FreezeAccountObject UnFreezeAccount(PCPSWebInput webInput,
			FreezeAccountObject faObj) throws PCPSApplicationException {
		// 1. 交易检查阶段

		// 入口参数检查
		checkFreezeArgs(faObj);

		// 检查销售机构日终状态
		checkSaleBranchDayOff(webInput.getOperBranchNo());

		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(faObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new PCPSApplicationException("", "操作员无效!");

		// 操作员对应的发卡商号
		String oper_IssueCompanyNo = PCPSUtil.getICNoByBranchNo(sysOpUser
				.getOperBranchNo());

		// 检索卡信息
		ActivateCard ac = activateCardDaoImpl
				.getActivateCardByCardNo(faObj.cardNo);
		if (ac == null)
			throw new PCPSApplicationException("", "卡号" + faObj.cardNo + "无效!");

		// 检索制卡控制批次
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(ac.getBatchNo());

		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(mcc.getIssueCompanyNo());

		// 操作员与卡的归属必须是同一发卡商
		if (!PCPSUtil.compareObject(oper_IssueCompanyNo, issueCompany
				.getIssueCompanyNo()))
			throw new PCPSApplicationException("", "卡不存在!");

		// 检查卡是否已经注销
		// 判断销卡状态 -- 不等于未销卡
		if (!PCPSUtil.compareObject(ac.getCloseStatus(),
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"卡" + ac.getCardNo() + "已经注销!");

		// 2. 请求帐户子系统冻结服务
		Map<BigInteger, BigInteger> masAccNoMap = new HashMap<BigInteger, BigInteger>();
		masAccNoMap.put(ac.getMasterAccNo(), BigInteger.ZERO);

		// 手续费扣除
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_freezeSolution,
				ac.getCardNo(), null, issueCompany.getTranDate(), ac
						.getBalance());
		BigInteger fee = ifp.getFee();
		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_freezeSolution);
		faObj.fee = fee;
		// 如果是试算,把试算结果返回
		if (faObj.isTrail) {
			return faObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !faObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}
		// 检查收费模式
		if (!PCPSUtil.compareObject(faObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(faObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");
		// 检查优惠的手续费
		if ((faObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(faObj.discountFee) > 0
				|| faObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (faObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(faObj.authOperId, faObj.authPwd, faObj.operId,
					sysOpUser.getOperBranchNo());
		else
			faObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(faObj.discountFee);
		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(faObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			faObj.cashFee = BigInteger.ZERO;
			faObj.cardFee = factfee;
		} else {
			faObj.cashFee = factfee;
			faObj.cardFee = BigInteger.ZERO;
		}

		accountBusinessImpl.FreezeAccount(issueCompany.getIssueCompanyNo(),
				faObj.operId, "[解冻结]" + faObj.remark, masAccNoMap, true);

		// 卡事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		Date occurTime = pcpsCommonDaoImpl.getDatabaseSysTime();
		String accSeqNo = null;
		// 如果需要延期,则执行扣费动作
		if (faObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = faObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = faObj.cardNo;
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = faObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "卡冻结手续费");
			// 保留流水号
			accSeqNo = paidResult.accseqno;
			// 设置返回余额
			faObj.balance = paidResult.cardbalance.get(faObj.cardNo);
		}

		// 现金收入记帐
		if (faObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					faObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid, faObj.operId,
					occurTime, "卡冻结手续费");

		// 业务单号
		String cardEventOrderSeq = pcpsCommonDaoImpl.getOrderNumber(occurTime,
				webInput.getOperBranchNo());
		faObj.orderSeqNo = evid.toString();// 返回的CardEventId

		// 4.记载卡事件日志
		CardEventLog cel = new CardEventLog();
		cel.setBalance(faObj.balance);
		cel.setFee(fee);
		cel.setCardFee(faObj.cardFee);
		cel.setCashFee(faObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(faObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(faObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(faObj.operId);
		cel.setRemark(faObj.remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(ac.getCardNo());
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setExpired(ac.getExpired());
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(occurTime);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_FREEZE_FREE);
		cardEventLogDaoImpl.insert(cel);
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Edit, "卡解冻结", "CardNo:" + cel.getCardNo());

		return faObj;
	}

	/**
	 * 批量卡解冻结
	 * 
	 * @param eeObj
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public FreezeAccountObject batchUnFreezeAccount(PCPSWebInput input,
			FreezeAccountObject faObj) throws PCPSApplicationException {
		if (input == null || PCPSUtil.isEmpty(input.getOperBranchNo())
				|| input.getOperId() == null) {
			throw new CardTranApplicationException("", "", "登录用户必输参数为空!");
		}
		if (PCPSUtil.isEmpty(faObj.startCardSeqNo)
				|| PCPSUtil.isEmpty(faObj.endCardSeqNo)) {
			throw new CardTranApplicationException("", "", "起始顺序号或者终止顺序号为空!");
		}
		if (faObj.count.intValue() < 1) {
			throw new CardTranApplicationException("", "", "卡张数不可小于1张卡!");
		}

		if (PCPSUtil.isEmpty(faObj.remark)) {
			throw new CardTranApplicationException("", "", "备注为空!");
		}

		if (!faObj.startCardSeqNo.substring(0, 12).equals(
				faObj.endCardSeqNo.substring(0, 12))) {
			throw new CardTranApplicationException("", "", "起始终止卡序号不在同一批次中!");
		}

		String start = faObj.startCardSeqNo.substring(12, 18);
		String end = faObj.endCardSeqNo.substring(12, 18);
		int selCount = Integer.parseInt(end) - Integer.parseInt(start) + 1;
		if (faObj.count.intValue() != selCount) {
			throw new CardTranApplicationException("", "", "解冻结卡顺序号不连续!");
		}

		String batchNo = faObj.startCardSeqNo.substring(0, 12);
		String cardSeqNo = "";
		Integer start_i = Integer.parseInt(start);
		Integer end_i = start_i + faObj.count;
		ActivateCard ac = null;
		FreezeAccountObject obj = null;
		BigInteger totalFee = BigInteger.ZERO;
		// 2.新系统卡序号
		if (faObj.startCardSeqNo.trim().length() == 18) {
			for (int i = start_i; i < end_i; i++) {
				obj = new FreezeAccountObject();
				cardSeqNo = batchNo + String.format("%06d", i);
				ac = activateCardDaoImpl.getActivateCardByCardSeqNo(cardSeqNo);
				if (ac == null) {
					throw new CardTranApplicationException("", "",
							"激活卡列表中不存在顺序号为“" + cardSeqNo + "”卡!");
				}
				obj.amount = ac.getBalance();
				obj.operId = input.getOperId();
				obj.cardNo = ac.getCardNo();
				obj.remark = faObj.remark;
				obj.isTrail = faObj.isTrail;
				obj.chargeMode = faObj.chargeMode;
				obj = UnFreezeAccount(input, obj);
				totalFee = totalFee.add(obj.fee);
			}
		}
		// 3.旧系统卡序号
		else {
			String br = faObj.startCardSeqNo.substring(0, 6);
			Integer start_b = Integer.parseInt(faObj.startCardSeqNo.substring(
					6, 12));
			Integer end_b = Integer.parseInt(faObj.endCardSeqNo
					.substring(6, 12));
			for (int i = start_b; i < end_b; i++) {
				obj = new FreezeAccountObject();
				cardSeqNo = br + String.format("%06d", i);
				ac = activateCardDaoImpl.getActivateCardByCardSeqNo(cardSeqNo);
				if (ac == null) {
					throw new CardTranApplicationException("", "",
							"激活卡列表中不存原始系统中顺序号为“" + cardSeqNo + "”卡!");
				}
				obj.amount = ac.getBalance();
				obj.operId = input.getOperId();
				obj.cardNo = ac.getCardNo();
				obj.remark = faObj.remark;
				obj.isTrail = faObj.isTrail;
				obj.chargeMode = faObj.chargeMode;
				obj = UnFreezeAccount(input, obj);
				totalFee = totalFee.add(obj.fee);
			}
		}
		// 如果是试算,把试算结果返回
		if (faObj.isTrail) {
			faObj.fee = totalFee;
			return faObj;
		}
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(input, SysOperLog.operType_Edit,
				"批量卡解冻结", "startCardSeqNo: " + faObj.startCardSeqNo
						+ "endCardSeqNo" + faObj.endCardSeqNo);
		return faObj;
	}

	/**
	 * 获取有效的赎回扣费类型
	 * 
	 * @param issueCompany
	 *            发卡商对象
	 * @param cardClassic
	 *            卡种类对象
	 * @return
	 * @throws PCPSApplicationException
	 */
	// private FeeType getValidateRedempFeeType(IssueCompany issueCompany,
	// CardClassic cardClassic) throws PCPSApplicationException {
	// FeeType feeType = new FeeType();
	//
	// // 取发卡商默认
	// if (PCPSUtil.compareObject(cardClassic.getRedempFeeType(),
	// CardClassic.CARDCLASSIC_REDEMP_FEETYPE_REF_ISSUE)) {
	// if (PCPSUtil.compareObject(issueCompany.getRedempFeeType(),
	// IssueCompany.ISSUECOMPANY_REDEMP_FEETYPE_FIXED))
	// feeType.feeType = FeeType.FEETYPE_FIXED;
	// else if (PCPSUtil.compareObject(issueCompany.getRedempFeeType(),
	// IssueCompany.ISSUECOMPANY_REDEMP_FEETYPE_AMOUNT_RATIO))
	// feeType.feeType = FeeType.FEETYPE_RATIO;
	// else
	// throw new PCPSApplicationException("", "发卡商"
	// + issueCompany.getIssueCompanyNo() + "赎回扣费模式"
	// + issueCompany.getRedempFeeType() + "无效!");
	// feeType.fixedFee = issueCompany.getRedempFixFee().intValue();
	// feeType.ratio = issueCompany.getRedempFixRatio().intValue();
	// if (feeType.fixedFee < 0
	// && feeType.feeType == FeeType.FEETYPE_FIXED)
	// throw new PCPSApplicationException("", "发卡商"
	// + issueCompany.getIssueCompanyNo() + "赎回扣费固定金额"
	// + issueCompany.getExtendFixFee().toString() + "无效!");
	// if ((feeType.ratio < 0 || feeType.ratio >= 10000)
	// && feeType.feeType == FeeType.FEETYPE_RATIO)
	// throw new PCPSApplicationException("", "发卡商"
	// + issueCompany.getIssueCompanyNo() + "赎回扣费按余额比率"
	// + issueCompany.getExtendFeeRatio().toString() + "无效!");
	// return feeType;
	// }
	//
	// if (PCPSUtil.compareObject(cardClassic.getRedempFeeType(),
	// CardClassic.CARDCLASSIC_REDEMP_FEETYPE_FIXED))
	// feeType.feeType = FeeType.FEETYPE_FIXED;
	// else if (PCPSUtil.compareObject(cardClassic.getRedempFeeType(),
	// CardClassic.CARDCLASSIC_REDEMP_FEETYPE_AMOUNT_RATIO))
	// feeType.feeType = FeeType.FEETYPE_RATIO;
	// else
	// throw new PCPSApplicationException("", "卡种类"
	// + cardClassic.getCardClassicName() + "赎回扣费模式"
	// + cardClassic.getRedempFeeType() + "无效!");
	// feeType.fixedFee = cardClassic.getRedempFixFee().intValue();
	// feeType.ratio = cardClassic.getRedempFixRatio().intValue();
	// if (feeType.fixedFee < 0 && feeType.feeType == FeeType.FEETYPE_FIXED)
	// throw new PCPSApplicationException("", "卡种类"
	// + cardClassic.getCardClassicName() + "赎回扣费固定金额"
	// + cardClassic.getRedempFixFee().toString() + "无效!");
	// if ((feeType.ratio < 0 || feeType.ratio >= 10000)
	// && feeType.feeType == FeeType.FEETYPE_RATIO)
	// throw new PCPSApplicationException("", "卡种类"
	// + cardClassic.getCardClassicName() + "赎回扣费按余额比率"
	// + cardClassic.getRedempFixRatio().toString() + "无效!");
	// return feeType;
	// }
	/**
	 * 赎回验证入口参数检查
	 * 
	 * @param rdObj
	 * @throws PCPSApplicationException
	 */
	private void checkVerifyRedempArgs(RedempObject rdObj)
			throws PCPSApplicationException {

		if (rdObj == null)
			throw new PCPSApplicationException("", "入口参数为空!");

		// 卡号
		if (PCPSUtil.isEmpty(rdObj.cardNo))
			throw new PCPSApplicationException("", "卡号为空!");

		if (rdObj.amount == null)
			rdObj.amount = BigInteger.ZERO;

		int result = rdObj.amount.compareTo(BigInteger.ZERO);

		// 金额
		if (result < 0)
			throw new PCPSApplicationException("", "赎回金额非法!");

		// 当有金额时必须验证密码的存在性
		if (rdObj.verifyPwd && PCPSUtil.isEmpty(rdObj.pwd))
			throw new PCPSApplicationException("", "赎回确认时必须输入密码!");

		if (!rdObj.verifyPwd)
			rdObj.pwd = null;

		// 操作员
		if (rdObj.operId == null)
			throw new PCPSApplicationException("", "操作员为空!");
	}

	/**
	 * 计算某发卡商某赎回单某卡最大可赎回资金
	 * 
	 * @param issueCompany
	 * @param ac
	 * @return
	 * @throws PCPSApplicationException
	 */
	private BigInteger getMaxRedempAmount(IssueCompany issueCompany,
			String cardNo) throws PCPSApplicationException {
		// 计算时间以赎回单创建时间为准
		if (issueCompany.getRedempLimit() < 0)
			throw new PCPSApplicationException("", "发卡商赎回期限设置有误!");

		// 检索卡信息
		ActivateCard ac = activateCardDaoImpl.getActivateCardByCardNo(cardNo);
		if (ac == null)
			throw new PCPSApplicationException("", "卡号" + cardNo + "无效!");

		// 检索制卡控制批次
		MakeCardControl mcc = makeCardControlDaoImpl
				.getMakeCardControlByBatchNo(ac.getBatchNo());

		if (!PCPSUtil.compareObject(mcc.getIssueCompanyNo(), issueCompany
				.getIssueCompanyNo()))
			throw new PCPSApplicationException("", "卡" + cardNo + "归属与发卡商不一致!");

		// 取卡种类
		CardClassic cardClassic = cardClassicDaoImpl
				.getCardClassicByCardClassicId(ac.getCardClassicId());

		// 判断卡种类是否允许赎回
		if (!PCPSUtil.compareObject(cardClassic.getAllowRedemp(),
				CardClassic.CARDCLASSIC_ALLOW_REDEMP))
			throw new PCPSApplicationException("", "该卡不允许赎回!");

		// 检查卡是否能办理业务
		isCardCanDoTrans(ac);

		Date maxTime = pcpsCommonDaoImpl.getDatabaseSysTime();
		java.util.Calendar cal = java.util.Calendar.getInstance();
		cal.setTime(maxTime);
		cal.add(java.util.Calendar.HOUR_OF_DAY, 0 - issueCompany
				.getRedempLimit());
		maxTime = cal.getTime();

		// 计算理论上最大的可赎回金额
		BigInteger maxRedemp = masterAccountTransferDetailDaoImpl
				.getMaxTheoryRedemp(ac.getMasterAccNo(), null, maxTime);

		// 主帐户
		MasterAccount masacc = masterAccountDaoImpl
				.getMasterAccountByMasterAccNo(ac.getMasterAccNo());

		// 帐户可动用资金
		// BigInteger maxBal = masacc.getBalance().subtract(
		// masacc.getFreezeAmount()).subtract(masacc.getAuthDeposit())
		// .subtract(masacc.getAuthRedemp());
		BigInteger maxBal = masacc.getBalance().subtract(
				masacc.getFreezeAmount()).subtract(masacc.getAuthRedemp());
		// 如果理论上可赎回资金大于帐户可动用资金
		if (maxRedemp.compareTo(maxBal) > 0)
			maxRedemp = maxBal;

		// 赎回金额修正
		if (maxRedemp.compareTo(BigInteger.ZERO) < 0)
			maxRedemp = BigInteger.ZERO;

		return maxRedemp;
	}

	/**
	 * 验证赎回单卡赎回信息
	 * 
	 * @param rdObj
	 *            入口参数
	 * @throws PCPSApplicationException
	 */
	public RedempObject VerifyCardRedempOrder(RedempObject rdObj)
			throws PCPSApplicationException {
		// 1. 入口参数检查
		checkVerifyRedempArgs(rdObj);

		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(rdObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new PCPSApplicationException("", "操作员无效!");

		// 操作员必须是销售机构的操作员
		SaleBranch saleBranch = saleBranchDaoImpl
				.getSaleBranchBySaleBranchNo(sysOpUser.getOperBranchNo());
		if (saleBranch == null)
			throw new PCPSApplicationException("", "非销售机构的操作员!");

		// 检查密码及发生额
		// 非试算需要检查密码
		chkCardAttribute(rdObj.cardNo, rdObj.pwd, rdObj.amount);

		// 操作员对应的发卡商号
		String oper_IssueCompanyNo = PCPSUtil.getICNoByBranchNo(sysOpUser
				.getOperBranchNo());

		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(oper_IssueCompanyNo);

		// 计算理论上最大的可赎回金额
		BigInteger maxRedemp = getMaxRedempAmount(issueCompany, rdObj.cardNo);

		if (maxRedemp.compareTo(BigInteger.ZERO) <= 0)
			throw new PCPSApplicationException("", "卡号" + rdObj.cardNo
					+ "资金暂不支持赎回!");

		// 最大可赎回资金
		rdObj.maxRedempAmount = maxRedemp;

		if (maxRedemp.compareTo(rdObj.amount) < 0
				&& rdObj.amount.compareTo(BigInteger.ZERO) > 0)
			throw new PCPSApplicationException("", "卡号" + rdObj.cardNo
					+ "赎回资金超限!");

		if (rdObj.amount.compareTo(BigInteger.ZERO) == 0)
			rdObj.amount = maxRedemp;

		ActivateCard ac = activateCardDaoImpl
				.getActivateCardByCardNo(rdObj.cardNo);
		if (ac == null)
			throw new PCPSApplicationException("", "卡号" + rdObj.cardNo + "无效!");

		// 赎回手续费
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_redemp, ac.getCardNo(), ac
						.getCardClassicId(), issueCompany.getTranDate(),
				rdObj.amount);

		BigInteger fee = ifp.getFee();

		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		rdObj.factRedempAmount = rdObj.amount.subtract(fee);
		rdObj.fee = fee;
		rdObj.beforeBalance = ac.getBalance();
		rdObj.afterBalance = rdObj.beforeBalance.subtract(rdObj.amount);

		return rdObj;
	}

	/**
	 * 金额有效性判断
	 * 
	 * @param amt
	 * @return
	 */
	private boolean isValidAmount(BigInteger amt, boolean inclZero) {
		if (amt == null)
			return false;

		int res = amt.compareTo(BigInteger.ZERO);
		if (res < 0)
			return false;

		if (res > 0)
			return true;

		if (inclZero && res == 0)
			return true;

		return false;
	}

	/**
	 * 获取验证通过的赎回单赎回列表
	 * 
	 * @param redempOrder
	 * @return
	 * @throws PCPSApplicationException
	 */
	private Map<BigInteger, RedempOrderDetail> getValidateRedempOrderDetail(
			IssueCompany issueCompany, RedempOrder redempOrder,
			boolean isConfirm) throws PCPSApplicationException {

		BigInteger redempOrderId = redempOrder.getRedempOrderId();

		List<RedempOrderDetail> rodlist = redempOrderDetailDaoImpl
				.getRedempOrderDetailListByRedempOrderId(redempOrder
						.getRedempOrderId());
		if (rodlist == null || rodlist.size() < 1)
			throw new PCPSApplicationException("", "赎回单" + redempOrderId
					+ "不存在!");

		Map<BigInteger, RedempOrderDetail> rodmap = new HashMap<BigInteger, RedempOrderDetail>();

		BigInteger totalRedempAmount = BigInteger.ZERO;
		BigInteger totalFee = BigInteger.ZERO;
		BigInteger totalFactRedempAmount = BigInteger.ZERO;

		for (RedempOrderDetail rod : rodlist) {
			if (rodmap.containsKey(rod.getMasterAccNo()))
				throw new PCPSApplicationException("", "赎回单" + redempOrderId
						+ "存在多笔重复卡" + rod.getCardNo() + "的赎回记录!");

			// 确认时验证
			if (isConfirm) {
				if (!isValidAmount(rod.getRedempAmount(), false)
						|| !isValidAmount(rod.getFactRedempAmount(), false)
						|| !isValidAmount(rod.getFee(), true))
					throw new PCPSApplicationException("", "赎回单"
							+ redempOrderId + "卡" + rod.getCardNo()
							+ "赎回金额有误,请更正!");

				// 重新计算
				BigInteger maxRedempAmount = getMaxRedempAmount(issueCompany,
						rod.getCardNo());

				// 最大可赎回金额不满足
				if (maxRedempAmount.compareTo(rod.getRedempAmount()) < 0)
					throw new PCPSApplicationException("", "赎回单"
							+ redempOrderId + "卡" + rod.getCardNo()
							+ "赎回金额超过限制,请更正!");

				ActivateCard ac = activateCardDaoImpl
						.getActivateCardByCardNo(rod.getCardNo());

				// 赎回手续费
				IssueFeePolicy ifp = issueFeePolicyBusinessImpl
						.calcCardHolderFee(issueCompany.getIssueCompanyNo(),
								redempOrder.getSaleBranchNo(),
								IssueFeePolicy.IFPolicy_busiType_redemp, rod
										.getCardNo(), ac.getCardClassicId(),
								issueCompany.getTranDate(), rod
										.getRedempAmount());
				BigInteger fee = ifp.getFee();

				if (BigInteger.ZERO.compareTo(fee) > 0)
					throw new PCPSApplicationException("", "手续费计算错!");

				// 计算实际赎回额
				BigInteger factRedempAmount = rod.getRedempAmount().subtract(
						fee);
				// 2013年4月21修改
				factRedempAmount = factRedempAmount.add(rod.getFee()).subtract(
						rod.getFactFee());
				// 比较其一致性
				if (!factRedempAmount.equals(rod.getFactRedempAmount())
						|| !fee.equals(rod.getFee()))
					throw new PCPSApplicationException("", "赎回单"
							+ redempOrderId + "卡" + rod.getCardNo() + "实际赎回金额"
							+ factRedempAmount.intValue() / 100 + "与"
							+ rod.getFactRedempAmount().intValue() / 100
							+ "或手续费" + fee.intValue() / 100 + "与"
							+ rod.getFee().intValue() / 100 + "不相等,请更正!");
				// 2013年4月21修改
				if (!rod.getRedempAmount().equals(
						factRedempAmount.add(rod.getFactFee())))
					throw new PCPSApplicationException("", "赎回单"
							+ redempOrderId + "卡" + rod.getCardNo()
							+ "实际赎回金额+手续费<>总赎回金额,请更正!");
			}

			totalRedempAmount = totalRedempAmount.add(rod.getRedempAmount());
			totalFactRedempAmount = totalFactRedempAmount.add(rod
					.getFactRedempAmount());
			totalFee = totalFee.add(rod.getFee());

			rodmap.put(rod.getMasterAccNo(), rod);
		}

		/**
		 * 确认时验证比较合计数
		 */
		if (isConfirm) {
			if (!totalRedempAmount.equals(redempOrder.getTotalRedempAmount())
					|| !totalFactRedempAmount.equals(redempOrder
							.getTotalFactRedempAmount())
					|| !totalFee.equals(redempOrder.getTotalFee()))
				throw new PCPSApplicationException("", String.format(
						"赎回单%s合计赎回金额等不一致(%s,%s,%s,%s,%s,%s),请更正!",
						redempOrderId.toString(), totalRedempAmount.toString(),
						redempOrder.getTotalRedempAmount().toString(),
						totalFactRedempAmount.toString(), redempOrder
								.getTotalFactRedempAmount().toString(),
						totalFee.toString(), redempOrder.getTotalFee()));
		}

		return rodmap;
	}

	/**
	 * 调整指定的赎回单明细资金到主帐户
	 * 
	 * @param rod
	 * @param isConfirm
	 * @throws PCPSApplicationException
	 */
	private void adjustMasterAccountAuthRedempFunds(RedempOrderDetail rod,
			boolean isConfirm) throws PCPSApplicationException {
		MasterAccount masacc = masterAccountDaoImpl
				.getMasterAccountByMasterAccNoForUpdate(rod.getMasterAccNo());
		if (!PCPSUtil.compareObject(masacc.getCardNo(), rod.getCardNo()))
			throw new PCPSApplicationException("", "赎回单"
					+ rod.getRedempOrderId() + "卡号" + rod.getCardNo() + "异常!");

		BigInteger redempAmount = rod.getRedempAmount();

		// 确认增加,其他减少
		if (!isConfirm)
			redempAmount = BigInteger.ZERO.subtract(redempAmount);
		masacc.setAuthRedemp(masacc.getAuthRedemp().add(redempAmount));

		// 执行修改
		masterAccountDaoImpl.update(masacc);
	}

	/**
	 * 调整赎回单每个赎回卡的赎回资金到相应的主帐户待审核赎回资金,并验证费用的合理性
	 * 
	 * @param redempOrderId
	 * @param isConfirm
	 * @throws PCPSApplicationException
	 */
	private void adjustRedempFunds(BigInteger redempOrderId, boolean isConfirm)
			throws PCPSApplicationException {
		// 验证赎回单
		RedempOrder redempOrder = redempOrderDaoImpl
				.getRedempOrderForUpdate(redempOrderId);
		if (redempOrder == null)
			throw new PCPSApplicationException("", "赎回单" + redempOrderId
					+ "不存在!");

		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(redempOrder
						.getIssueCompanyNo());

		// 取有效的赎回单明细信息
		Map<BigInteger, RedempOrderDetail> rodmap = getValidateRedempOrderDetail(
				issueCompany, redempOrder, isConfirm);

		// 逐笔增加或减少待审核的赎回资金
		for (Map.Entry<BigInteger, RedempOrderDetail> rodentry : rodmap
				.entrySet())
			adjustMasterAccountAuthRedempFunds(rodentry.getValue(), isConfirm);
	}

	/**
	 * 赎回单确认(只验证,增加本单资金为待审核)
	 * 
	 * @param redempOrderId
	 *            赎回单ID
	 * @throws PCPSApplicationException
	 */
	public void ConfirmRedempOrder(BigInteger redempOrderId)
			throws PCPSApplicationException {
		adjustRedempFunds(redempOrderId, true);
	}

	/**
	 * 赎回单确认取消或撤销(只验证,减少本单待审核资金)
	 * 
	 * @param redempOrderId
	 *            赎回单ID
	 * @throws PCPSApplicationException
	 */
	public void CancelConfirmRedempOrder(PCPSWebInput webInput,
			BigInteger redempOrderId) throws PCPSApplicationException {
		adjustRedempFunds(redempOrderId, false);
	}

	/**
	 * 赎回单扣款记帐
	 * 
	 * @param redempOrderId
	 *            赎回单ID
	 * @param operId
	 *            操作员ID
	 * @throws PCPSApplicationException
	 */
	public void AccountRedempOrder(BigInteger redempOrderId, BigInteger operId)
			throws PCPSApplicationException {
		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl.getSysOpUserByOperId(operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new PCPSApplicationException("", "操作员无效!");

		// 验证赎回单
		RedempOrder redempOrder = redempOrderDaoImpl
				.getRedempOrderForUpdate(redempOrderId);
		if (redempOrder == null)
			throw new PCPSApplicationException("", "赎回单" + redempOrderId
					+ "不存在!");

		// 赎回单状态必须处于
		if (!PCPSUtil.compareObject(redempOrder.getOrderStatus(),
				RedempOrder.OrderStatus_SecPass))
			throw new PCPSApplicationException("", "赎回单" + redempOrderId
					+ "必须处于已终审状态!");

		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(redempOrder
						.getIssueCompanyNo());
		IssueBranch ib = issueBranchDaoImpl
				.getIssueBranchByIssueBranchNo(sysOpUser.getOperBranchNo());

		// 判断操作员是否IssueBranch的操作员
		if (ib == null || PCPSUtil.isEmpty(ib.getIssueBranchNo()))
			throw new PCPSApplicationException("", "非发卡机构的操作员!");

		// 取有效的赎回单明细信息
		Map<BigInteger, RedempOrderDetail> rodmap = getValidateRedempOrderDetail(
				issueCompany, redempOrder, false);

		// 减少待审核的赎回资金
		for (Map.Entry<BigInteger, RedempOrderDetail> rodentry : rodmap
				.entrySet())
			adjustMasterAccountAuthRedempFunds(rodentry.getValue(), false);

		// 交易时间
		Date tranTime = pcpsCommonDaoImpl.getDatabaseSysTime();

		// 请求帐户子系统记帐服务
		ArrayList<AccountParam> accountParamList = new ArrayList<AccountParam>();
		List<CardAccountParam> caplist = new ArrayList<CardAccountParam>();

		// 生成caplist
		for (Map.Entry<BigInteger, RedempOrderDetail> rodentry : rodmap
				.entrySet()) {
			RedempOrderDetail rod = rodentry.getValue();
			CardAccountParam cap = new CardAccountParam();
			cap.cardNo = rod.getCardNo();
			cap.paidAmount = rod.getFactRedempAmount();
			cap.feeAmount = rod.getFee();
			caplist.add(cap);
		}

		List<CardAccountDetail> all_cad = getCardAccountDetail(caplist);

		// 把all_cad转换成accountParamList
		for (CardAccountDetail cad : all_cad) {
			AccountParam ap = new AccountParam();
			ap.subAccNo = cad.SubAccNo;
			// 全部为借方记帐
			ap.debitAmount = cad.paidAmount.add(cad.feeAmount);
			ap.creditAmount = BigInteger.ZERO;
			if (cad.paidAmount.compareTo(BigInteger.ZERO) > 0) {
				ap.tranType = AccountSystemAddTradDetail.TRANTYPE_REDEMP;
				ap.summary = "[赎回]" + redempOrderId;
			} else {
				ap.tranType = AccountSystemAddTradDetail.TRANTYPE_FEE;
				ap.summary = "[手续费][赎回]" + redempOrderId;
			}
			// 加入到记帐列表
			accountParamList.add(ap);
		}

		// 调用核心帐户子系统记帐接口记帐
		String accseqno = accountBusinessImpl.Account(issueCompany
				.getIssueCompanyNo(), issueCompany.getTranDate(), tranTime,
				"REDEMP_" + redempOrderId, operId, "[赎回]" + redempOrderId,
				accountParamList);

		// 记载转出明细
		MasterAccountTransferDetail matd = null;
		for (Map.Entry<BigInteger, RedempOrderDetail> rodentry : rodmap
				.entrySet()) {
			RedempOrderDetail rod = rodentry.getValue();
			matd = new MasterAccountTransferDetail();
			matd.setAccSeqNo(accseqno);
			matd.setMasterAccNo(rod.getMasterAccNo());
			matd.setBankAccountId(redempOrder.getPayeeAccountId());
			matd.setTicketId(redempOrderId);
			matd.setTranTime(tranTime);
			matd.setTransferInAmount(BigInteger.ZERO);
			// 应记载实际赎回金额还是实际赎回金额 + 手续费,暂定后者,需要和业务沟通.2013.1.31
			matd.setTransferOutAmount(rod.getRedempAmount());
			masterAccountTransferDetailDaoImpl.insert(matd);
		}

		// 批量更新卡余额
		/*
		 * for (Map.Entry<BigInteger, RedempOrderDetail> rodentry : rodmap
		 * .entrySet()) { RedempOrderDetail rod = rodentry.getValue();
		 * MasterAccount ma = masterAccountDaoImpl
		 * .getMasterAccountByMasterAccNo(rod.getMasterAccNo()); ActivateCard ac =
		 * activateCardDaoImpl
		 * .getActivateCardByCardNoForUpdate(rod.getCardNo());
		 * ac.setBalance(ma.getBalance()); }
		 */

		// 修正赎回单状态
		String oldStatus = redempOrder.getOrderStatus();

		// 状态变更为已扣帐
		redempOrder.setOrderStatus(RedempOrder.OrderStatus_Debit);
		redempOrder.setAccSeqNo(accseqno);

		// 2013.07.13 add by yxb
		redempOrder.setLastRedempDate(issueCompany.getTranDate());

		redempOrderDaoImpl.update(redempOrder);

		// 4. 登记赎回单状态迁移明细
		RedempOrderActionDetail road = new RedempOrderActionDetail();

		road.setRedempOrderId(redempOrder.getRedempOrderId());
		road.setActionTime(tranTime);
		road.setOperId(operId);
		road.setInitialStatus(oldStatus);
		road.setEndStatus(redempOrder.getOrderStatus());
		road.setActionType(RedempOrderActionDetail.RedOrdDetail_Type_ACC);
		road.setRemark("[赎回扣款记帐]" + accseqno);

		redempOrderActionDetailDaoImpl.insertRedempOrderActionDetail(road);
	}

	/**
	 * 获得完整有效的充值列表<卡号、充值金额>
	 * 
	 * @param issueCompany
	 * @param depositOrder
	 * @param allcardamt
	 * @param amtdirection
	 *            发生额方向
	 * @return
	 * @throws PCPSApplicationException
	 */
	private Map<String, ActivateCard> getAllValidateCardOfDepositOrder(
			IssueCompany issueCompany, DepositOrder depositOrder,
			Map<String, BigInteger> allcardamt, BigInteger amtdirection)
			throws PCPSApplicationException {
		List<DepositOrderDetail> dodlist = depositOrderDetailDaoImpl
				.getDepositOrderDetailListByDepositOrderId(depositOrder
						.getDepositOrderId());
		if (dodlist == null || dodlist.size() < 1)
			throw new PCPSApplicationException("", "充值单"
					+ depositOrder.getDepositOrderId() + "无有效的充值明细!");

		Map<BigInteger, CardClassic> allcardclassic = new HashMap<BigInteger, CardClassic>();
		Map<String, ActivateCard> allcard = new HashMap<String, ActivateCard>();
		BigInteger totalamt = BigInteger.ZERO;

		for (DepositOrderDetail dod : dodlist) {
			// 卡号不允许重复
			if (allcardamt.containsKey(dod.getCardNo()))
				throw new PCPSApplicationException("", "充值单"
						+ depositOrder.getDepositOrderId() + "待充值卡号"
						+ dod.getCardNo() + "重复!");
			// 充值金额必须为正数
			if (dod.getDepositAmount() == null
					|| BigInteger.ZERO.compareTo(dod.getDepositAmount()) >= 0)
				throw new PCPSApplicationException("", "充值单"
						+ depositOrder.getDepositOrderId() + "待充值卡号"
						+ dod.getCardNo() + "充值金额" + dod.getDepositAmount()
						+ "非法!");

			totalamt = totalamt.add(dod.getDepositAmount());

			// 判定充值卡的合法性
			ActivateCard ac = activateCardDaoImpl
					.getActivateCardByCardNoForUpdate(dod.getCardNo());
			if (ac == null)
				throw new PCPSApplicationException("", "充值单"
						+ depositOrder.getDepositOrderId() + "待充值卡号"
						+ dod.getCardNo() + "不存在!");
			// 操作员对应的发卡商号
			String card_IssueCompanyNo = PCPSUtil.getICNoByBranchNo(ac
					.getSaleBranchNo());
			if (!PCPSUtil.compareObject(card_IssueCompanyNo, issueCompany
					.getIssueCompanyNo()))
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_INVALID, "卡" + ac.getCardNo()
								+ "属其他发卡商的卡!");

			// 判断状态
			if (!PCPSUtil.compareObject(ac.getCloseStatus(),
					ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL))
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_INVALID, "卡" + ac.getCardNo()
								+ "已经注销!");

			// 是否挂失
			if (PCPSUtil.compareObject(ac.getLossStatus(),
					ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED)
					|| PCPSUtil.compareObject(ac.getLossStatus(),
							ActivateCard.ACTIVATECARD_LOSSSTATUS_TEMP_LOSSED))
				throw new CardTranApplicationException(
						TuxedoRespCode.RC_INVALID, "卡" + ac.getCardNo()
								+ "已经挂失!");

			// 判断卡种类是否允许充值
			if (!allcardclassic.containsKey(ac.getCardClassicId())) {
				CardClassic cc = cardClassicDaoImpl
						.getCardClassicByCardClassicId(ac.getCardClassicId());
				if (cc == null)
					throw new CardTranApplicationException(
							TuxedoRespCode.RC_INVALID, "卡" + ac.getCardNo()
									+ "卡种类无效!");
				if (!PCPSUtil.compareObject(cc.getAllowDeposit(),
						CardClassic.CARDCLASSIC_ALLOWDEPOSIT_RECHARGE))
					throw new CardTranApplicationException(
							TuxedoRespCode.RC_INVALID, "卡" + ac.getCardNo()
									+ "所属卡种类不允许充值!");
				allcardclassic.put(ac.getCardClassicId(), cc);
			}

			// 本次充值后金额超限检查
			BigInteger newbal = ac.getBalance().add(
					dod.getDepositAmount().multiply(amtdirection));
			if (issueCompany.getEachCardOwnerLimit().compareTo(BigInteger.ZERO) > 0
					&& newbal.compareTo(issueCompany.getEachCardOwnerLimit()) > 0
					&& ac.getOwnerId() == null)
				throw new PCPSApplicationException("", "卡" + dod.getCardNo()
						+ "充值后余额超限,请登记实名持卡人信息!");

			// 余额超限检查
			checkBalanceLimit(dod.getCardNo(), newbal, issueCompany,
					allcardclassic.get(ac.getCardClassicId()));

			// 加入到充值列表
			allcardamt.put(dod.getCardNo(), dod.getDepositAmount());

			// 加入到返回列表
			allcard.put(dod.getCardNo(), ac);
		}

		// 判断合计金额
		if (!totalamt.equals(depositOrder.getTotalDepositAmount()))
			throw new CardTranApplicationException(TuxedoRespCode.RC_INVALID,
					"充值单" + depositOrder.getDepositOrderId() + "总计充值额与明细汇总不一致!");

		return allcard;
	}

	/**
	 * 删除为0的入口
	 * 
	 * @param allcardamt
	 */
	private void removeZeroEntry(Map<BigInteger, BigInteger> allcardamt) {
		Map<BigInteger, BigInteger> allzero = new HashMap<BigInteger, BigInteger>();

		for (Map.Entry<BigInteger, BigInteger> tot : allcardamt.entrySet()) {
			if (tot.getValue().compareTo(BigInteger.ZERO) <= 0)
				allzero.put(tot.getKey(), BigInteger.ZERO);
		}

		for (Map.Entry<BigInteger, BigInteger> zero : allzero.entrySet())
			allcardamt.remove(zero.getKey());
	}

	/**
	 * 计算Q值最大的1个卡号
	 * 
	 * @param alreadypaid
	 * @param allcardamt
	 * @return
	 */
	private BigInteger getMaxQValue(Map<BigInteger, BigInteger> alreadypaid,
			Map<BigInteger, BigInteger> allcardamt) {
		BigDecimal curmax = BigDecimal.ZERO;
		BigInteger masaccno = null;

		for (Map.Entry<BigInteger, BigInteger> allentry : allcardamt.entrySet()) {
			BigInteger masno = allentry.getKey();
			BigInteger allamt = allentry.getValue();
			BigInteger allseat = alreadypaid.get(masno);
			if (allseat == null)
				allseat = BigInteger.ZERO;
			allseat = allseat.add(BigInteger.ONE);
			BigDecimal allamt_q = new BigDecimal(allamt.toString());
			allamt_q = allamt_q.multiply(allamt_q);
			BigDecimal seat_q = new BigDecimal(allseat.toString())
					.multiply(new BigDecimal(allseat.add(BigInteger.ONE)
							.toString()));
			BigDecimal cmax = allamt_q
					.divide(seat_q, 6, RoundingMode.HALF_DOWN);
			if (cmax.compareTo(curmax) > 0) {
				masaccno = masno;
				curmax = cmax;
			}
		}

		return masaccno;
	}

	/**
	 * 将指定银行指定金额公平分配到map中
	 * 
	 * @param bankid
	 * @param bankamt
	 * @param allcardamt
	 */
	private Map<BigInteger, BigInteger> distributePaid(BigInteger bankid,
			BigInteger bankamt, Map<BigInteger, BigInteger> allcardamt)
			throws PCPSApplicationException {

		Map<BigInteger, BigInteger> alreadypaid = new HashMap<BigInteger, BigInteger>();

		// 删除为0的入口数据
		removeZeroEntry(allcardamt);
		if (allcardamt.size() == 0)
			return alreadypaid;

		// 计算allcardamt的总和
		BigInteger total = BigInteger.ZERO;
		for (Map.Entry<BigInteger, BigInteger> tot : allcardamt.entrySet())
			total = total.add(tot.getValue());

		if (total.compareTo(BigInteger.ZERO) <= 0)
			return alreadypaid;

		// 先平均分配整数部分
		// 本笔银行付款信息折算到每分钱的贡献度
		BigDecimal bd = new BigDecimal(bankamt.toString()).divide(
				new BigDecimal(total.toString()), 10, RoundingMode.HALF_DOWN);

		for (Map.Entry<BigInteger, BigInteger> allentry : allcardamt.entrySet()) {
			BigInteger masaccno = allentry.getKey();
			BigInteger cardamt = allentry.getValue();
			BigInteger curamt = bd.multiply(new BigDecimal(cardamt.toString()))
					.setScale(0, RoundingMode.HALF_UP).toBigInteger();
			// 折算后不足1分钱,继续
			if (curamt.compareTo(BigInteger.ZERO) <= 0)
				continue;
			BigInteger oldamt = alreadypaid.remove(masaccno);
			if (oldamt == null)
				oldamt = BigInteger.ZERO;
			if (cardamt.compareTo(oldamt.add(curamt)) < 0)
				curamt = cardamt.subtract(oldamt);
			curamt = curamt.compareTo(bankamt) <= 0 ? curamt : bankamt;
			oldamt = oldamt.add(curamt);
			bankamt = bankamt.subtract(curamt);
			alreadypaid.put(masaccno, oldamt);
			// 如果已经分配完毕
			if (bankamt.compareTo(BigInteger.ZERO) <= 0)
				break;
		}

		// 分配剩余部分,按Q值法,每次分配1分钱
		while (bankamt.compareTo(BigInteger.ZERO) > 0) {
			BigInteger masaccno = getMaxQValue(alreadypaid, allcardamt);
			BigInteger oldamt = alreadypaid.remove(masaccno);
			if (oldamt == null)
				oldamt = BigInteger.ZERO;
			oldamt = oldamt.add(BigInteger.ONE);
			alreadypaid.put(masaccno, oldamt);
			bankamt = bankamt.subtract(BigInteger.ONE);
		}

		// 对alreadypaid中的每个记录,将allcardamt中的记录减去
		for (Map.Entry<BigInteger, BigInteger> allentry : alreadypaid
				.entrySet()) {
			BigInteger masaccno = allentry.getKey();
			BigInteger amt = allentry.getValue();
			BigInteger oldamt = allcardamt.remove(masaccno);
			if (oldamt == null)
				continue;
			oldamt = oldamt.subtract(amt);
			if (oldamt.compareTo(BigInteger.ZERO) <= 0)
				continue;
			allcardamt.put(masaccno, oldamt);
		}

		return alreadypaid;
	}

	/**
	 * 获取有效的充值转账付款分配信息
	 * 
	 * @param depositOrder
	 *            销售单
	 * @param allcardamt
	 *            卡与充值金额的map
	 * @param allac
	 *            卡号与activateCard的map
	 * @param allpaidmap
	 *            转账分配map
	 * @return 总的现金付款额
	 * @throws PCPSApplicationException
	 */
	private BigInteger getValidatePaidMap(DepositOrder depositOrder,
			Map<String, BigInteger> allcardamt,
			Map<String, ActivateCard> allac,
			Map<BigInteger, Map<BigInteger, BigInteger>> allpaidmap)
			throws PCPSApplicationException {

		List<DepositOrderPaidDetail> allpaiddetail = depositOrderPaidDetailDaoImpl
				.getDepositOrderPaidDetailListByDepositOrderId(depositOrder
						.getDepositOrderId());
		if (allpaiddetail == null)
			throw new PCPSApplicationException("", "充值单"
					+ depositOrder.getDepositOrderId() + "无有效的付款信息!");

		BigInteger totalcardamt = BigInteger.ZERO;
		// 计算allcardamt金额之和
		for (Map.Entry<String, BigInteger> cardentry : allcardamt.entrySet())
			totalcardamt = totalcardamt.add(cardentry.getValue());

		BigInteger cashpaid = BigInteger.ZERO;
		BigInteger transferpaid = BigInteger.ZERO;
		BigInteger totalpaid = BigInteger.ZERO;
		BigInteger totalfee = BigInteger.ZERO;
		BigInteger totalcardamtpaid = BigInteger.ZERO;

		Map<BigInteger, BigInteger> bankpaid = new HashMap<BigInteger, BigInteger>();

		// 计算总的付款情况
		for (DepositOrderPaidDetail dopd : allpaiddetail) {
			if (PCPSUtil.compareObject(dopd.getPaidClass(),
					DepositOrderPaidDetail.PAIDDETAIL_paidClass_sale))
				totalcardamtpaid = totalcardamtpaid.add(dopd.getPaidAmount());
			if (PCPSUtil.compareObject(dopd.getPaidClass(),
					DepositOrderPaidDetail.PAIDDETAIL_paidClass_fee)) {
				totalfee = totalfee.add(dopd.getPaidAmount());
				continue;
			}
			if (PCPSUtil.compareObject(dopd.getPaidType(),
					DepositOrderPaidDetail.DEPOSITOPD_PAIDTYPE_CASH))
				cashpaid = cashpaid.add(dopd.getPaidAmount());
			else if (PCPSUtil.compareObject(dopd.getPaidType(),
					DepositOrderPaidDetail.DEPOSITOPD_PAIDTYPE_CHECK)
					|| PCPSUtil
							.compareObject(
									dopd.getPaidType(),
									DepositOrderPaidDetail.DEPOSITOPD_PAIDTYPE_TRANSFER)) {
				transferpaid = transferpaid.add(dopd.getPaidAmount());
				BigInteger paccid = dopd.getPaidAccountId();
				if (paccid == null)
					paccid = BigInteger.ZERO;
				BigInteger curbankpaid = bankpaid.remove(paccid);
				if (curbankpaid == null)
					curbankpaid = BigInteger.ZERO;
				curbankpaid = curbankpaid.add(dopd.getPaidAmount());
				// 仅保存有效的付款银行帐户信息
				if (curbankpaid.compareTo(BigInteger.ZERO) != 0)
					bankpaid.put(paccid, curbankpaid);
			} else
				throw new PCPSApplicationException("", "充值单"
						+ depositOrder.getDepositOrderId() + "存在无效的付款类型"
						+ dopd.getPaidType() + "!");
		}

		totalpaid = cashpaid.add(transferpaid);

		// 现金视为特殊的ID
		bankpaid.put(BigInteger.ZERO, cashpaid);

		// 不能存在非法的付款信息
		if (cashpaid.compareTo(BigInteger.ZERO) < 0
				|| transferpaid.compareTo(BigInteger.ZERO) < 0
				|| totalpaid.compareTo(BigInteger.ZERO) <= 0
				|| totalfee.compareTo(BigInteger.ZERO) < 0
				|| totalcardamt.compareTo(depositOrder.getTotalDepositAmount()) != 0
				|| totalcardamtpaid.compareTo(totalcardamt) != 0
				|| totalfee.compareTo(depositOrder.getFactFee()) != 0
				|| totalcardamtpaid.add(totalfee).compareTo(
						depositOrder.getAlreayPaidAmount()) != 0)
			throw new PCPSApplicationException("", "充值单"
					+ depositOrder.getDepositOrderId() + "付款信息有误!");

		// 产生工作对象
		Map<BigInteger, BigInteger> allcardamt_work = new HashMap<BigInteger, BigInteger>();
		for (Map.Entry<String, BigInteger> allentry : allcardamt.entrySet())
			allcardamt_work.put(allac.get(allentry.getKey()).getMasterAccNo(),
					allentry.getValue());

		// 将转账信息平均分配到每一个卡号,最后一个卡号在本帐号的付款金额采用减法计算
		for (Map.Entry<BigInteger, BigInteger> bankpaidentry : bankpaid
				.entrySet()) {
			BigInteger bankpaidamt = bankpaidentry.getValue();
			int result = bankpaidamt.compareTo(BigInteger.ZERO);
			if (result == 0)
				continue;
			if (result < 0)
				throw new PCPSApplicationException("", "充值单"
						+ depositOrder.getDepositOrderId() + "付款帐户总付款信息有误!");

			Map<BigInteger, BigInteger> alreadypaid = distributePaid(
					bankpaidentry.getKey(), bankpaidamt, allcardamt_work);

			// 加入到返回列表
			for (Map.Entry<BigInteger, BigInteger> allentry : alreadypaid
					.entrySet()) {
				Map<BigInteger, BigInteger> curbank = allpaidmap.get(allentry
						.getKey());
				if (curbank == null) {
					curbank = new HashMap<BigInteger, BigInteger>();
					allpaidmap.put(allentry.getKey(), curbank);
				}
				curbank.put(bankpaidentry.getKey(), allentry.getValue());
			}
		}

		return cashpaid;
	}

	/**
	 * 获取总计现金付款总额
	 * 
	 * @param depositOrder
	 *            销售单
	 * @param allcardamt
	 *            卡与充值金额的map
	 * @param allac
	 *            卡号与activateCard的map
	 * @param allpaidmap
	 *            转账分配map
	 * @return 总的现金付款额
	 * @throws PCPSApplicationException
	 */
	private BigInteger getAllCashPaid(DepositOrder depositOrder)
			throws PCPSApplicationException {

		List<DepositOrderPaidDetail> allpaiddetail = depositOrderPaidDetailDaoImpl
				.getDepositOrderPaidDetailListByDepositOrderId(depositOrder
						.getDepositOrderId());
		if (allpaiddetail == null)
			throw new PCPSApplicationException("", "充值单"
					+ depositOrder.getDepositOrderId() + "无有效的付款信息!");

		BigInteger cashpaid = BigInteger.ZERO;

		// 计算总的现金付款情况
		for (DepositOrderPaidDetail dopd : allpaiddetail) {
			if (PCPSUtil.compareObject(dopd.getPaidType(),
					DepositOrderPaidDetail.DEPOSITOPD_PAIDTYPE_CASH)
					|| PCPSUtil.compareObject(dopd.getPaidType(),
							DepositOrderPaidDetail.DEPOSITOPD_PAIDTYPE_CHECK))
				cashpaid = cashpaid.add(dopd.getPaidAmount());
			else if (PCPSUtil.compareObject(dopd.getPaidType(),
					DepositOrderPaidDetail.DEPOSITOPD_PAIDTYPE_TRANSFER)) {
			} else
				throw new PCPSApplicationException("", "充值单"
						+ depositOrder.getDepositOrderId() + "存在无效的付款类型"
						+ dopd.getPaidType() + "!");
		}

		// 不能存在非法的付款信息
		if (cashpaid.compareTo(BigInteger.ZERO) < 0)
			throw new PCPSApplicationException("", "充值单"
					+ depositOrder.getDepositOrderId() + "付款信息有误!");

		return cashpaid;
	}

	/**
	 * 获得有效的销售员信息
	 * 
	 * @param depositOrder
	 * @return
	 * @throws PCPSApplicationException
	 */
	private ArrayList<SalesGroup> getValidSalesByDepositOrder(
			DepositOrder depositOrder) throws PCPSApplicationException {

		ArrayList<SalesGroup> sglist = new ArrayList<SalesGroup>();

		List<DepositOrderSalesDetail> dosdlist = depositOrderSalesDetailDaoImpl
				.getDepositOrderSalesDetailListByDepositOrderId(depositOrder
						.getDepositOrderId());

		if (dosdlist == null || dosdlist.size() < 1)
			return null;

		Integer degree = 0;
		for (DepositOrderSalesDetail sosd : dosdlist) {
			SalesGroup sg = new SalesGroup();
			sg.setSalesGroupId(null);
			sg.setSalesId(sosd.getSalesId());
			BigDecimal bd = new BigDecimal(sosd.getSalesAmount())
					.divide(new BigDecimal(depositOrder.getTotalDepositAmount()));
			sg.setDegreeOfcontribution(bd.toBigInteger());
			sglist.add(sg);
			degree += bd.toBigInteger().intValue();
		}

		if (degree > 101 || degree < 0)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					"", "充值单" + depositOrder.getDepositOrderId().toString()
							+ "销售员业绩贡献度无效!");

		return sglist;
	}

	/**
	 * 更新充值待审核资金
	 * 
	 * @param allcardamt
	 * @param allac
	 * @param isCancel
	 *            是否撤销
	 * @throws PCPSApplicationException
	 */
	private void updateAuthDeposit(Map<String, BigInteger> allcardamt,
			Map<String, ActivateCard> allac, boolean isCancel)
			throws PCPSApplicationException {

		for (Map.Entry<String, BigInteger> amtentry : allcardamt.entrySet()) {
			String cardNo = amtentry.getKey();
			BigInteger amt = amtentry.getValue();
			BigInteger masaccno = allac.get(cardNo).getMasterAccNo();
			MasterAccount masacc = masterAccountDaoImpl
					.getMasterAccountByMasterAccNoForUpdate(masaccno);

			// 如果撤销,金额变号
			if (isCancel)
				amt = BigInteger.ZERO.subtract(amt);

			// 更新主帐户充值待审核资金
			masacc.setAuthDeposit(masacc.getAuthDeposit().add(amt));
			if (masacc.getAuthDeposit().compareTo(BigInteger.ZERO) < 0)
				throw new PCPSApplicationException("", "卡" + cardNo
						+ "待审核充值资金无效!");

			masterAccountDaoImpl.update(masacc);
		}
	}

	/**
	 * 审核充值资金
	 * 
	 * @param allcardamt
	 * @param allac
	 * @param isCancel
	 * @throws PCPSApplicationException
	 */
	private void AuthDepositAmount(Map<String, BigInteger> allcardamt,
			Map<String, ActivateCard> allac, boolean isCancel)
			throws PCPSApplicationException {

		for (Map.Entry<String, BigInteger> amtentry : allcardamt.entrySet()) {
			String cardNo = amtentry.getKey();
			BigInteger amt = amtentry.getValue();
			BigInteger masaccno = allac.get(cardNo).getMasterAccNo();
			MasterAccount masacc = masterAccountDaoImpl
					.getMasterAccountByMasterAccNoForUpdate(masaccno);

			// 如果是撤销审核
			if (isCancel)
				amt = BigInteger.ZERO.subtract(amt);

			// 更新主帐户充值待审核资金
			masacc.setAuthDeposit(masacc.getAuthDeposit().subtract(amt));
			if (masacc.getAuthDeposit().compareTo(BigInteger.ZERO) < 0)
				throw new PCPSApplicationException("", "卡" + cardNo
						+ "待审核充值资金无效!");

			masterAccountDaoImpl.update(masacc);
		}
	}

	/**
	 * 充值单记帐,仅增加卡的充值待审核资金
	 * 
	 * @param depositOrderId
	 *            充值单ID
	 * @param operId
	 *            操作员ID
	 * @throws PCPSApplicationException
	 *             异常信息
	 */
	public void AccountDepositOrder(PCPSWebInput webInput,
			BigInteger depositOrderId, BigInteger operId)
			throws PCPSApplicationException {
		// 1. 交易检查阶段

		// 入口参数检查
		if (depositOrderId == null || operId == null)
			throw new PCPSApplicationException("", "入口参数无效!");

		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl.getSysOpUserByOperId(operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new PCPSApplicationException("", "操作员无效!");

		// 操作员必须是销售机构的操作员
		SaleBranch saleBranch = saleBranchDaoImpl
				.getSaleBranchBySaleBranchNo(sysOpUser.getOperBranchNo());
		if (saleBranch == null)
			throw new PCPSApplicationException("", "非销售机构的操作员!");

		// 操作员对应的发卡商号
		String oper_IssueCompanyNo = PCPSUtil.getICNoByBranchNo(sysOpUser
				.getOperBranchNo());

		// 发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(oper_IssueCompanyNo);

		// 检查充值单
		DepositOrder depositOrder = depositOrderDaoImpl
				.getDepositOrderForUpdate(depositOrderId);
		if (depositOrder == null)
			throw new PCPSApplicationException("", "无此充值单" + depositOrderId
					+ "!");

		// 充值单与操作员的机构号必须一致
		if (!PCPSUtil.compareObject(depositOrder.getSaleBranchNo(), saleBranch
				.getSaleBranchNo()))
			throw new PCPSApplicationException("", "充值单非本机构业务单!");

		// 充值单类型 -- 必须为批量充值
		if (!PCPSUtil.compareObject(depositOrder.getDepositType(),
				DepositOrder.DEPORDER_DEPOSITTYPE_MORE))
			throw new PCPSApplicationException("", "充值单类型不对!");

		// 充值单状态 -- 必须处于已付清状态
		if (!PCPSUtil.compareObject(depositOrder.getOrderStatus(),
				DepositOrder.DEPORDER_ORDERSTATUS_HAVEPAID))
			throw new PCPSApplicationException("", "充值单状态非法!");

		// 总充值金额必须与总付款金额一致
		if (!PCPSUtil.compareObject(depositOrder.getAlreayPaidAmount(),
				depositOrder.getTotalDepositAmount().add(
						depositOrder.getFactFee())))
			throw new PCPSApplicationException("", String.format(
					"总充值金额(%s)加实收手续费(%s)与总付款金额(%s)不一致!", depositOrder
							.getTotalDepositAmount().toString(), depositOrder
							.getFactFee().toString(), depositOrder
							.getAlreayPaidAmount().toString()));

		// 获得完整有效的充值列表<卡号、充值金额>
		Map<String, BigInteger> allcardamt = new HashMap<String, BigInteger>();
		Map<String, ActivateCard> allac = getAllValidateCardOfDepositOrder(
				issueCompany, depositOrder, allcardamt, BigInteger.ONE);

		// 将转账付款信息分配到每一个主帐户上
		Map<BigInteger, Map<BigInteger, BigInteger>> allpaidmap = new HashMap<BigInteger, Map<BigInteger, BigInteger>>();

		// 本充值单现金 总付款金额
		BigInteger totalcashpaid = getValidatePaidMap(depositOrder, allcardamt,
				allac, allpaidmap);

		// 充值金额是否超限
		if (issueCompany.getDepositTransferLimit().compareTo(BigInteger.ZERO) > 0
				&& depositOrder.getTotalDepositAmount().compareTo(
						issueCompany.getDepositTransferLimit()) > 0
				&& totalcashpaid.compareTo(BigInteger.ZERO) > 0)
			throw new PCPSApplicationException("", "充值金额超限,请全部用转账方式充值!");

		// 4. 更新充值待审核资金
		updateAuthDeposit(allcardamt, allac, false);

		// 5. 更新充值单记帐流水号 & 状态
		// depositOrder
		// .setOrderStatus(DepositOrder.DEPORDER_ORDERSTATUS_HAVERECHARGE);
		// depositOrderDaoImpl.updateDepositOrder(depositOrder);
	}

	/**
	 * 撤销充值单记帐 -- 有问题20130612
	 * 
	 * @param depositOrderId
	 *            充值单ID
	 * @param operId
	 *            操作员ID
	 * @param remark
	 *            撤销原因或备注
	 * @throws PCPSApplicationException
	 *             异常信息
	 */
	public void CancelAccountDepositOrder(PCPSWebInput webInput,
			BigInteger depositOrderId, BigInteger operId, String remark)
			throws PCPSApplicationException {
		// 1. 交易检查阶段

		// 入口参数检查
		if (depositOrderId == null || operId == null)
			throw new PCPSApplicationException("", "入口参数无效!");

		if (PCPSUtil.isEmpty(remark))
			throw new PCPSApplicationException("", "必须输入撤销原因!");

		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl.getSysOpUserByOperId(operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new PCPSApplicationException("", "操作员无效!");

		// 操作员必须是销售机构的操作员
		SaleBranch saleBranch = saleBranchDaoImpl
				.getSaleBranchBySaleBranchNo(sysOpUser.getOperBranchNo());
		if (saleBranch == null)
			throw new PCPSApplicationException("", "非销售机构的操作员!");

		// 操作员对应的发卡商号
		String oper_IssueCompanyNo = PCPSUtil.getICNoByBranchNo(sysOpUser
				.getOperBranchNo());

		// 发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(oper_IssueCompanyNo);

		// 检查充值单
		DepositOrder depositOrder = depositOrderDaoImpl
				.getDepositOrderForUpdate(depositOrderId);
		if (depositOrder == null)
			throw new PCPSApplicationException("", "无此充值单" + depositOrderId
					+ "!");

		// 充值单与操作员的机构号必须一致
		if (!PCPSUtil.compareObject(depositOrder.getSaleBranchNo(), saleBranch
				.getSaleBranchNo()))
			throw new PCPSApplicationException("", "充值单非本机构业务单!");

		// 充值单类型 -- 必须为批量充值
		if (!PCPSUtil.compareObject(depositOrder.getDepositType(),
				DepositOrder.DEPORDER_DEPOSITTYPE_MORE))
			throw new PCPSApplicationException("", "充值单类型不对!");

		// 充值单状态 -- 必须处于已充值状态
		if (!PCPSUtil.compareObject(depositOrder.getOrderStatus(),
				DepositOrder.DEPORDER_ORDERSTATUS_HAVERECHARGE))
			throw new PCPSApplicationException("", "充值单状态必须为已充值状态!");

		// 总充值金额必须与总付款金额一致
		if (!PCPSUtil.compareObject(depositOrder.getAlreayPaidAmount(),
				depositOrder.getTotalDepositAmount().add(
						depositOrder.getFactFee())))
			throw new PCPSApplicationException("", "总充值金额与总付款金额不一致!");

		// 获得完整有效的充值列表<卡号、充值金额>
		Map<String, BigInteger> allcardamt = new HashMap<String, BigInteger>();
		Map<String, ActivateCard> allac = getAllValidateCardOfDepositOrder(
				issueCompany, depositOrder, allcardamt, BigInteger.ZERO
						.subtract(BigInteger.ONE));

		// 本充值单现金 + 现金支票总付款金额
		BigInteger totalcashpaid = getAllCashPaid(depositOrder);

		// 验证上次的记帐流水号
		if (PCPSUtil.isEmpty(depositOrder.getLastDepositAccSeqNo()))
			throw new PCPSApplicationException("", "充值单上次记帐流水号为空!");

		// 验证充值单原记帐MAC
		String macstr = getDepositOrderActivateMac(depositOrder
				.getDepositOrderId(), depositOrder.getLastDepositAccSeqNo(),
				operId, totalcashpaid);
		if (!PCPSUtil.compareObject(depositOrder.getLastDepositMac(), macstr))
			throw new PCPSApplicationException("", "非当前操作员办理的记帐业务!");

		// 2. 机构信用度反向记帐 -- 假如存在现金付款的情况
		Date tranTime = pcpsCommonDaoImpl.getDatabaseSysTime();

		/*
		 * if (totalcashpaid.compareTo(BigInteger.ZERO) > 0) saleBranch =
		 * saleBranchCaptialAccountOnlyCredit(saleBranch .getSaleBranchNo(),
		 * issueCompany.getTranDate(), BigInteger.ZERO,
		 * BigInteger.ZERO.subtract(totalcashpaid),
		 * SaleCapitalDetail.TRANTYPE_CANCELDEPOSITCASH, depositOrder
		 * .getDepositOrderId(), operId, tranTime, "[充值撤销]" + remark);
		 */

		// 3. 帐户子系统撤销记帐
		String accSeqNo = accountBusinessImpl.AccountCancel(issueCompany
				.getIssueCompanyNo(), issueCompany.getTranDate(), tranTime,
				"C_DEPOSIT_" + depositOrder.getDepositOrderId().toString(),
				depositOrder.getLastDepositAccSeqNo(), operId, "[充值撤销"
						+ depositOrderId.toString() + "]" + remark);

		// 4. 更新充值待审核资金&卡余额&累计充值额
		updateAuthDeposit(allcardamt, allac, true);

		// 5. 更新充值单记帐流水号 & 状态
		String oldOrderStatus = depositOrder.getOrderStatus();
		depositOrder.setLastCancelDepositAccSeqNo(accSeqNo);
		depositOrder.setOrderStatus(DepositOrder.DEPORDER_ORDERSTATUS_HAVEPAID);
		depositOrderDaoImpl.updateDepositOrder(depositOrder);

		// 6. 登记充值单状态迁移明细
		DepositOrderActionDetail depositOrderActionDetail = new DepositOrderActionDetail();

		depositOrderActionDetail.setDepositOrderId(depositOrder
				.getDepositOrderId());
		depositOrderActionDetail.setActionTime(tranTime);
		depositOrderActionDetail.setOperId(operId);
		depositOrderActionDetail.setInitialStatus(oldOrderStatus);
		depositOrderActionDetail.setEndStatus(depositOrder.getOrderStatus());
		depositOrderActionDetail
				.setActionType(DepositOrderActionDetail.DEPOSITOAD_ACTIONTYPE_CANCELDEPOSIT);
		depositOrderActionDetail.setRemark("[充值记帐撤销]" + remark);

		depositOrderActionDetailDaoImpl
				.insertDepositOrderActionDetail(depositOrderActionDetail);
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Edit, "撤销充值单记账", "DepositOrderId: "
						+ depositOrderActionDetail.getDepositOrderId());
	}

	/**
	 * 更新卡累计充值金额
	 * 
	 * @param allcardamt
	 * @param allac
	 * @param isCancel
	 *            是否撤销
	 * @throws PCPSApplicationException
	 */
	private void updateTotalDeposit(Map<String, BigInteger> allcardamt,
			Map<String, ActivateCard> allac, boolean isCancel)
			throws PCPSApplicationException {

		for (Map.Entry<String, BigInteger> amtentry : allcardamt.entrySet()) {
			String cardNo = amtentry.getKey();
			BigInteger amt = amtentry.getValue();

			// 如果撤销,金额变号
			if (isCancel)
				amt = BigInteger.ZERO.subtract(amt);

			// 更新卡累计充值额
			ActivateCard ac = activateCardDaoImpl
					.getActivateCardByCardNoForUpdate(cardNo);
			ac.setTotalDeposit(ac.getTotalDeposit().add(amt));
			activateCardDaoImpl.update(ac);
		}
	}

	/**
	 * 审核充值单记帐,真正记帐
	 * 
	 * @param depositOrderId
	 *            充值单ID
	 * @param operId
	 *            操作员ID
	 * @param remark
	 *            审核通过原因或备注
	 * @throws PCPSApplicationException
	 *             异常信息
	 */
	public void AuthAccountDepositOrder(PCPSWebInput webInput,
			BigInteger depositOrderId, BigInteger operId, String remark)
			throws PCPSApplicationException {
		// 1. 交易检查阶段

		// 入口参数检查
		if (depositOrderId == null || operId == null)
			throw new PCPSApplicationException("", "入口参数无效!");

		// if (PCPSUtil.isEmpty(remark))
		// throw new PCPSApplicationException("", "必须输入撤销原因!");

		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl.getSysOpUserByOperId(operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new PCPSApplicationException("", "操作员无效!");

		String curbrchno = sysOpUser.getOperBranchNo();

		// 系统机构号 -- 确定机构类型
		SysBranch sysBranch = sysBranchDaoImpl
				.getSysBranchByBranchNo(curbrchno);

		if (!PCPSUtil.compareObject(sysBranch.getBranchType(),
				SysBranch.SYSBRANCH_ISSUEBRANCH))
			throw new CardTranApplicationException("", "必须是发卡商分支机构的操作员!");

		// 操作员对应的发卡商号
		String oper_IssueCompanyNo = PCPSUtil.getICNoByBranchNo(sysOpUser
				.getOperBranchNo());

		// 发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(oper_IssueCompanyNo);

		// 检查充值单
		DepositOrder depositOrder = depositOrderDaoImpl
				.getDepositOrderForUpdate(depositOrderId);
		if (depositOrder == null)
			throw new PCPSApplicationException("", "无此充值单" + depositOrderId
					+ "!");

		String saleBranch_IssueCompanyNo = depositOrder.getSaleBranchNo()
				.substring(0, 6);
		// 充值单与操作员的发卡商号必须一致
		if (!PCPSUtil.compareObject(saleBranch_IssueCompanyNo,
				oper_IssueCompanyNo))
			throw new PCPSApplicationException("", "充值单非发卡商的业务单!");

		// 充值单类型 -- 必须为批量充值
		if (!PCPSUtil.compareObject(depositOrder.getDepositType(),
				DepositOrder.DEPORDER_DEPOSITTYPE_MORE))
			throw new PCPSApplicationException("", "充值单类型不对!");

		// 充值单状态 -- 必须处于已充值状态
		if (!PCPSUtil.compareObject(depositOrder.getOrderStatus(),
				DepositOrder.SaleOrder_OrderStatus_AuthMoney))
			throw new PCPSApplicationException("", "充值单状态必须为资金已审状态!");

		// 充值单必须存在上次记帐流水号
		// if (PCPSUtil.isEmpty(depositOrder.getLastDepositAccSeqNo()))
		// throw new PCPSApplicationException("", "充值单上次记帐流水号为空!");

		// 总充值金额必须与总付款金额一致
		if (!PCPSUtil.compareObject(depositOrder.getAlreayPaidAmount(),
				depositOrder.getTotalDepositAmount().add(
						depositOrder.getFactFee())))
			throw new PCPSApplicationException("", "总充值金额与总付款金额不一致!");

		// 获得完整有效的充值列表<卡号、充值金额>
		Map<String, BigInteger> allcardamt = new HashMap<String, BigInteger>();
		Map<String, ActivateCard> allac = getAllValidateCardOfDepositOrder(
				issueCompany, depositOrder, allcardamt, BigInteger.ZERO);

		// 将转账付款信息分配到每一个主帐户上
		Map<BigInteger, Map<BigInteger, BigInteger>> allpaidmap = new HashMap<BigInteger, Map<BigInteger, BigInteger>>();

		// 本充值单现金 总付款金额
		BigInteger totalcashpaid = getValidatePaidMap(depositOrder, allcardamt,
				allac, allpaidmap);

		// 销售员列表
		ArrayList<SalesGroup> salesList = getValidSalesByDepositOrder(depositOrder);

		// 准备记帐参数
		ArrayList<DepositAccountParam> depositAccountParamList = new ArrayList<DepositAccountParam>();

		for (Map.Entry<String, BigInteger> entry : allcardamt.entrySet()) {
			DepositAccountParam ap = new DepositAccountParam();
			ap.masterAccNo = allac.get(entry.getKey()).getMasterAccNo();
			ap.depositAmount = entry.getValue();
			ap.remark = "[充值]" + depositOrderId.toString();
			depositAccountParamList.add(ap);
		}

		// 2. 机构信用度记帐 -- 假如存在现金付款的情况
		Date tranTime = pcpsCommonDaoImpl.getDatabaseSysTime();

		// 发卡商分支机构激活额度记帐 -- 仅与销售金额有关
		issueBranchBusinessImpl.activateAccount(curbrchno,
				CreditAccDetail.use_Ac_Bal, depositOrder
						.getTotalDepositAmount(),
				CreditAccDetail.orderType_DEPOSIT, depositOrderId, operId);

		/*
		 * if (totalcashpaid.compareTo(BigInteger.ZERO) > 0) saleBranch =
		 * saleBranchCaptialAccountOnlyCredit(saleBranch .getSaleBranchNo(),
		 * issueCompany.getTranDate(), BigInteger.ZERO, totalcashpaid,
		 * SaleCapitalDetail.TRANTYPE_CASH_DEPOSIT, depositOrder
		 * .getDepositOrderId(), operId, tranTime, "充值");
		 */

		// 3. 帐户子系统记帐
		DepositAccountResult dar = accountBusinessImpl.DepositAccount(
				issueCompany.getIssueCompanyNo(), depositOrder
						.getOpenBranchNo(), depositOrder.getDepositOrderId(),
				issueCompany.getTranDate(), tranTime, "DEPOSIT_"
						+ depositOrder.getDepositOrderId().toString(), operId,
				"[充值]" + depositOrderId.toString(), depositAccountParamList,
				salesList, allpaidmap);

		String accSeqNo = dar.accSeqNo;

		// 4. 减少充值待审核资金
		AuthDepositAmount(allcardamt, allac, false);

		// 更新累计充值金额
		updateTotalDeposit(allcardamt, allac, false);

		// 5. 更新充值单记帐流水号 & 状态
		String oldOrderStatus = depositOrder.getOrderStatus();
		depositOrder.setLastDepositAccSeqNo(accSeqNo);
		String macstr = getDepositOrderActivateMac(depositOrder
				.getDepositOrderId(), accSeqNo, operId, totalcashpaid);
		depositOrder.setLastDepositMac(macstr);
		depositOrder
				.setOrderStatus(DepositOrder.DEPORDER_ORDERSTATUS_HAVERECHARGE);

		// 2013.07.13 add by yxb
		depositOrder.setLastDepositDate(issueCompany.getTranDate());

		depositOrderDaoImpl.updateDepositOrder(depositOrder);

		// 6. 登记充值单状态迁移明细
		DepositOrderActionDetail depositOrderActionDetail = new DepositOrderActionDetail();

		depositOrderActionDetail.setDepositOrderId(depositOrder
				.getDepositOrderId());
		depositOrderActionDetail.setActionTime(tranTime);
		depositOrderActionDetail.setOperId(operId);
		depositOrderActionDetail.setInitialStatus(oldOrderStatus);
		depositOrderActionDetail.setEndStatus(depositOrder.getOrderStatus());
		depositOrderActionDetail
				.setActionType(DepositOrderActionDetail.DEPOSITOAD_ACTIONTYPE_AUDIT);
		depositOrderActionDetail.setRemark("充值审核记帐");

		depositOrderActionDetailDaoImpl
				.insertDepositOrderActionDetail(depositOrderActionDetail);

		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Edit, "充值单记账审核", "DepositOrderId: "
						+ depositOrderActionDetail.getDepositOrderId());
	}

	/**
	 * 撤销审核已记帐充值单 -- 有问题20130612
	 * 
	 * @param depositOrderId
	 *            充值单ID
	 * @param operId
	 *            操作员ID
	 * @param remark
	 *            审核通过原因或备注
	 * @throws PCPSApplicationException
	 *             异常信息
	 */
	public void CancelAuthAccountDepositOrder(PCPSWebInput webInput,
			BigInteger depositOrderId, BigInteger operId, String remark)
			throws PCPSApplicationException {
		// 1. 交易检查阶段

		// 入口参数检查
		if (depositOrderId == null || operId == null)
			throw new PCPSApplicationException("", "入口参数无效!");

		if (PCPSUtil.isEmpty(remark))
			throw new PCPSApplicationException("", "必须输入撤销审核原因!");

		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl.getSysOpUserByOperId(operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo()))
			throw new PCPSApplicationException("", "操作员无效!");

		// 操作员必须是发卡商的操作员
		if (sysOpUser.getOperBranchNo().trim().length() != 6)
			throw new PCPSApplicationException("", "非发卡商的操作员!");

		// 操作员对应的发卡商号
		String oper_IssueCompanyNo = PCPSUtil.getICNoByBranchNo(sysOpUser
				.getOperBranchNo());

		// 发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(oper_IssueCompanyNo);

		// 检查充值单
		DepositOrder depositOrder = depositOrderDaoImpl
				.getDepositOrderForUpdate(depositOrderId);
		if (depositOrder == null)
			throw new PCPSApplicationException("", "无此充值单" + depositOrderId
					+ "!");

		String saleBranch_IssueCompanyNo = depositOrder.getSaleBranchNo()
				.substring(0, 6);
		// 充值单与操作员的机构号必须一致
		if (!PCPSUtil.compareObject(saleBranch_IssueCompanyNo,
				oper_IssueCompanyNo))
			throw new PCPSApplicationException("", "充值单非发卡商的业务单!");

		// 充值单类型 -- 必须为批量充值
		if (!PCPSUtil.compareObject(depositOrder.getDepositType(),
				DepositOrder.DEPORDER_DEPOSITTYPE_MORE))
			throw new PCPSApplicationException("", "充值单类型不对!");

		// 充值单状态 -- 必须处于已充值状态
		if (!PCPSUtil.compareObject(depositOrder.getOrderStatus(),
				DepositOrder.DEPORDER_ORDERSTATUS_HAVERECHARGE))
			throw new PCPSApplicationException("", "充值单状态必须为已审核状态!");

		// 充值单必须存在上次记帐流水号
		if (PCPSUtil.isEmpty(depositOrder.getLastDepositAccSeqNo()))
			throw new PCPSApplicationException("", "充值单上次记帐流水号为空!");

		// 总充值金额必须与总付款金额一致
		if (!PCPSUtil.compareObject(depositOrder.getAlreayPaidAmount(),
				depositOrder.getTotalDepositAmount()))
			throw new PCPSApplicationException("", "总充值金额与总付款金额不一致!");

		// 获得完整有效的充值列表<卡号、充值金额>
		Map<String, BigInteger> allcardamt = new HashMap<String, BigInteger>();
		Map<String, ActivateCard> allac = getAllValidateCardOfDepositOrder(
				issueCompany, depositOrder, allcardamt, BigInteger.ZERO);

		// 交易时间
		Date tranTime = pcpsCommonDaoImpl.getDatabaseSysTime();

		// 4. 重新增加充值待审核资金
		AuthDepositAmount(allcardamt, allac, true);

		// 5. 更新充值单状态
		String oldOrderStatus = depositOrder.getOrderStatus();
		depositOrder
				.setOrderStatus(DepositOrder.DEPORDER_ORDERSTATUS_HAVERECHARGE);

		// 2013.07.13 add by yxb
		depositOrder.setLastCancelDepositDate(issueCompany.getTranDate());

		depositOrderDaoImpl.updateDepositOrder(depositOrder);

		// 6. 登记充值单状态迁移明细
		DepositOrderActionDetail depositOrderActionDetail = new DepositOrderActionDetail();

		depositOrderActionDetail.setDepositOrderId(depositOrder
				.getDepositOrderId());
		depositOrderActionDetail.setActionTime(tranTime);
		depositOrderActionDetail.setOperId(operId);
		depositOrderActionDetail.setInitialStatus(oldOrderStatus);
		depositOrderActionDetail.setEndStatus(depositOrder.getOrderStatus());
		depositOrderActionDetail
				.setActionType(DepositOrderActionDetail.DEPOSITOAD_ACTIONTYPE_AUDITCANCEL);
		depositOrderActionDetail.setRemark("[充值记帐撤销审核]" + remark);

		depositOrderActionDetailDaoImpl
				.insertDepositOrderActionDetail(depositOrderActionDetail);
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Edit, "撤销审核已记账充值单", "DepositOrderId: "
						+ depositOrderActionDetail.getDepositOrderId());
	}

	@Override
	public void updateCardEventLogVoucherNo(PCPSWebInput webInput,
			BigInteger cardEventLogId, String voucherNo, String businessType)
			throws PCPSApplicationException {
		// 1.入口参数检查
		if (webInput == null) {
			errException("入口参数无效!");
		}
		if (cardEventLogId == null) {
			errException("参数:卡特殊业务流水号未获取到!");
		}
		if (PCPSUtil.isEmpty(voucherNo)) {
			errException("参数:凭证号未获取到!");
		}
		if (PCPSUtil.isEmpty(businessType)) {
			errException("参数:凭证种类未获取到!");
		}
		List<VoucherBusinessBind> vbbList = voucherBusinessBindImpl
				.getVoucherBusinessBindByBusinessType(webInput, businessType,
						-1);
		if (vbbList == null || vbbList.size() < 1) {
			errException("未找到业务对应凭证种类!");
		}
		// 凭证种类Id
		BigInteger voucherId = vbbList.get(0).getVoucherId();
		CardEventLog cel = cardEventLogDaoImpl.getCardEventLog(cardEventLogId);
		if (cel == null) {
			errException("未找到该业务对应事件信息!");
		}
		// 更新凭证库存
		VoucherStock vs = new VoucherStock();
		vs.setVoucherId(voucherId);
		vs.setVoucherNo(voucherNo);
		VoucherStock serchVS = voucherStockDaoImpl.getVoucherStock(vs);
		if (serchVS == null
				|| !serchVS.getStatus().equals(VoucherStock.Status_0)) {
			String str = (serchVS.getStatus().equals("1")) ? "在途" : (serchVS
					.getStatus().equals("9")) ? "丢失、损坏等" : "";
			errException("凭证信息不存在或状态异常!" + str);
		}
		// 更新凭证库存
		serchVS.setStatus(VoucherStock.Status_2);
		voucherStockDaoImpl.updateVoucherStockByStatus(serchVS);
		// 插入库存出入库明细
		VoucherStockDetail voucherStockDetail = new VoucherStockDetail();
		voucherStockDetail.setIoOrderId(cardEventLogId);
		voucherStockDetail.setIssueCompanyNo(PCPSUtil
				.getIssueCompanyNo(webInput));
		voucherStockDetail.setBranchNo(webInput.getOperBranchNo());
		IssueCompany ic = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(PCPSUtil
						.getIssueCompanyNo(webInput));
		voucherStockDetail.setTranDate(ic.getTranDate());
		voucherStockDetail.setTranTime(pcpsCommonDaoImpl.getDatabaseSysTime());
		voucherStockDetail.setVoucherId(voucherId);
		voucherStockDetail.setStartVoucherNo(voucherNo);
		voucherStockDetail.setEndVoucherNo(voucherNo);
		voucherStockDetail.setCount(1);
		voucherStockDetail.setTranType(VoucherStockDetail.Status_4);
		voucherStockDetail.setOperId(webInput.getOperId());

		voucherStockDetailDaoImpl.insertVoucherStockDetail(voucherStockDetail);

		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Edit, "打印单据后修改卡特殊业务事件凭证信息", "voucherNo: "
						+ voucherNo);
		// 更新卡事件日志
		cel.setVoucherId(voucherId);
		cel.setVoucherNo(voucherNo);
		cardEventLogDaoImpl.updateCardEventLog(cel);
	}

	@Override
	public void updateCardLossVoucherNo(PCPSWebInput webInput,
			BigInteger cardLossId, String voucherNo, String businessType)
			throws PCPSApplicationException {
		// 1.入口参数检查
		if (webInput == null || cardLossId == null
				|| PCPSUtil.isEmpty(voucherNo)
				|| PCPSUtil.isEmpty(businessType)) {
			errException("入口参数无效!");
		}
		List<VoucherBusinessBind> vbbList = voucherBusinessBindImpl
				.getVoucherBusinessBindByBusinessType(webInput, businessType,
						-1);
		if (vbbList == null || vbbList.size() < 1) {
			errException("未找到业务对应凭证种类!");
		}

		// 凭证种类Id
		BigInteger voucherId = vbbList.get(0).getVoucherId();
		CardLoss cl = cardLossDao.getCardLossByCardLossIdForUpdate(cardLossId);
		if (cl == null) {
			errException("未找到该业务对应事件信息!");
		}

		// 更新凭证库存
		VoucherStock vs = new VoucherStock();
		vs.setVoucherId(voucherId);
		vs.setVoucherNo(voucherNo);
		VoucherStock serchVS = voucherStockDaoImpl.getVoucherStock(vs);
		if (serchVS == null
				|| !serchVS.getStatus().equals(VoucherStock.Status_0)) {
			String str = (serchVS.getStatus().equals("1")) ? "在途" : (serchVS
					.getStatus().equals("9")) ? "丢失、损坏等" : "";
			errException("凭证信息不存在或状态异常!" + str);
		}
		// 更新凭证库存
		serchVS.setStatus(VoucherStock.Status_2);
		voucherStockDaoImpl.updateVoucherStockByStatus(serchVS);
		// 插入库存出入库明细
		VoucherStockDetail voucherStockDetail = new VoucherStockDetail();
		voucherStockDetail.setIoOrderId(cardLossId);
		voucherStockDetail.setIssueCompanyNo(webInput.getOperBranchNo()
				.substring(0, 6));
		voucherStockDetail.setBranchNo(webInput.getOperBranchNo());
		IssueCompany ic = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(webInput.getOperBranchNo()
						.substring(0, 6));
		voucherStockDetail.setTranDate(ic.getTranDate());
		voucherStockDetail.setTranTime(pcpsCommonDaoImpl.getDatabaseSysTime());
		voucherStockDetail.setVoucherId(voucherId);
		voucherStockDetail.setStartVoucherNo(voucherNo);
		voucherStockDetail.setEndVoucherNo(voucherNo);
		voucherStockDetail.setCount(1);
		voucherStockDetail.setTranType(VoucherStockDetail.Status_4);
		voucherStockDetail.setOperId(webInput.getOperId());

		voucherStockDetailDaoImpl.insertVoucherStockDetail(voucherStockDetail);
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Edit, "打印单据后修改卡挂失事件凭证信息", "voucherNo: "
						+ voucherNo);
		// 更新卡事件日志
		cl.setVoucherId(voucherId);
		cl.setVoucherNo(voucherNo);
		cardLossDao.update(cl);
	}

	public void verifyCardPassword(String CardNo, String Pwd)
			throws PCPSApplicationException {
		// 检查密码
		chkCardAttribute(CardNo, Pwd, null);
	}

	@Override
	public void canCardPaidAtMerchantNo(String cardNo, String merchantNo)
			throws PCPSApplicationException {
		ActivateCard ac = activateCardDaoImpl
				.getActivateCardByCardNoOrSeqNo(cardNo);
		Merchant mrch = merchantDaoImpl.getMerchantByMerchantNo(merchantNo);
		canPaidOnMerchant(ac, mrch);
	}

	/**
	 * 解除卡密码锁定
	 * 
	 * @param webInput
	 * @param clObj
	 * @return
	 * @throws PCPSApplicationException
	 */
	@Override
	public CardLossObject resetPwdErrCnt(PCPSWebInput webInput,
			CardLossObject clObj) throws PCPSApplicationException {
		// 1. 参数检查
		if (clObj == null || PCPSUtil.isEmpty(clObj.cardNo)
				|| clObj.operId == null || clObj.branchNo == null)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		// 2. 如果是执行业务操作,检查备注是否为空
		if (!clObj.isTrail && PCPSUtil.isEmpty(clObj.remark)) {
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		}
		// 3. 检查卡相关属性
		ActivateCard ac = activateCardDaoImpl
				.getActivateCardByCardNoOrSeqNo(clObj.cardNo);
		// 检查是否能交易
		isCardCanDoTrans(ac);
		// 检查销售机构日终状态
		checkSaleBranchDayOff(webInput.getOperBranchNo());

		// 取操作员信息
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(clObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo())) {
			errException("操作员无效!");
		}
		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(PCPSUtil
						.getICNoByBranchNo(sysOpUser.getOperBranchNo()));
		// 判断卡状态
		if (ac.getPwdErrCnt() < issueCompany.getMaxPwdErrCnt()) {
			errException("操作失败,此卡" + clObj.cardNo + " 密码未锁定!");
		}
		if (!ac.getCloseStatus().equals(
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL)) {
			errException("操作失败,此卡" + clObj.cardNo + " 已销卡!");
		}
		if (ac.getManualLockStatus().equals(
				ActivateCard.ACTIVATECARD_MANUALLOCKSTATUS_LOCKED)) {
			errException("操作失败,此卡" + clObj.cardNo + " 处于锁定状态!");
		}

		// 取当前时间
		Date occurTime = pcpsCommonDaoImpl.getDatabaseSysTime();

		// 计算费用
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_pwdUnLock, ac.getCardNo(),
				null, issueCompany.getTranDate(), ac.getBalance());

		BigInteger fee = ifp.getFee();
		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_pwdUnLock);

		// 设置返回余额
		clObj.balance = ac.getBalance();
		clObj.fee = fee;

		// 如果是试算,把试算结果返回
		if (clObj.isTrail) {
			return clObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !clObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}
		// 检查收费模式
		if (!PCPSUtil.compareObject(clObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(clObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");
		// 检查优惠的手续费
		if ((clObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(clObj.discountFee) > 0
				|| clObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (clObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(clObj.authOperId, clObj.authPwd, clObj.operId,
					sysOpUser.getOperBranchNo());
		else
			clObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(clObj.discountFee);
		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(clObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			clObj.cashFee = BigInteger.ZERO;
			clObj.cardFee = factfee;
		} else {
			clObj.cashFee = factfee;
			clObj.cardFee = BigInteger.ZERO;
		}
		ac.setPwdErrCnt(0);
		ac.setLastPwdErrTime(null);
		activateCardDaoImpl.update(ac);

		// 卡事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		String accSeqNo = null;

		// 如果需要延期,则执行扣费动作
		if (clObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = clObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = clObj.cardNo;
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = clObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "解除卡密码锁定手续费");
			// 保留流水号
			accSeqNo = paidResult.accseqno;
			// 设置返回余额
			clObj.balance = paidResult.cardbalance.get(clObj.cardNo);
		}

		// 现金收入记帐
		if (clObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					clObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid, clObj.operId,
					occurTime, "解除卡密码锁定手续费");

		// 业务单号
		String cardEventOrderSeq = pcpsCommonDaoImpl.getOrderNumber(occurTime,
				clObj.branchNo);
		clObj.orderSeqNo = evid.toString();// 返回的CardEventId

		// 5.记载卡事件日志
		CardEventLog cel = new CardEventLog();
		cel.setBalance(clObj.balance);
		cel.setFee(fee);
		cel.setCardFee(clObj.cardFee);
		cel.setCashFee(clObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(clObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(clObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(clObj.operId);
		cel.setRemark(clObj.remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(ac.getCardNo());
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setExpired(ac.getExpired());
		cel.setNewExpired(null);
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(occurTime);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_PWDERRUNLOCK);
		cardEventLogDaoImpl.insert(cel);
		// 日志记录
		sysOperLogDaoImpl
				.insertSysOperLogInfo(webInput, SysOperLog.operType_Add,
						"解除卡密码锁定", "CardNo: " + ac.getCardNo());

		return clObj;
	}

	/**
	 * 卡手工锁定
	 * 
	 * @param webInput
	 * @param clObj
	 * @return
	 * @throws PCPSApplicationException
	 */
	@Override
	public CardLossObject cardManualLock(PCPSWebInput webInput,
			CardLossObject clObj) throws PCPSApplicationException {
		// 1. 参数检查
		if (clObj == null || PCPSUtil.isEmpty(clObj.cardNo)
				|| clObj.operId == null || clObj.branchNo == null)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		// 2. 如果是执行业务操作,检查备注是否为空
		if (!clObj.isTrail && PCPSUtil.isEmpty(clObj.remark)) {
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		}
		// 3. 检查卡相关属性
		ActivateCard ac = chkCardAttribute(clObj.cardNo, null, null);
		// 检查是否能交易
		isCardCanDoTrans(ac);
		// 检查销售机构日终状态
		checkSaleBranchDayOff(webInput.getOperBranchNo());

		// 判断卡状态
		if (ac.getLossStatus() != null
				&& (ac.getLossStatus().equals(
						ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED) || ac
						.getLossStatus()
						.equals(
								ActivateCard.ACTIVATECARD_LOSSSTATUS_TEMP_LOSSED))) {
			errException("操作失败,此卡" + clObj.cardNo + " 已挂失!");
		}
		if (!ac.getCloseStatus().equals(
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL)) {
			errException("操作失败,此卡" + clObj.cardNo + " 已销卡!");
		}
		if (ac.getManualLockStatus().equals(
				ActivateCard.ACTIVATECARD_MANUALLOCKSTATUS_LOCKED)) {
			errException("操作失败,此卡" + clObj.cardNo + " 已经处于锁定状态!");
		}

		// 取当前时间
		Date occurTime = pcpsCommonDaoImpl.getDatabaseSysTime();
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(clObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo())) {
			errException("操作员无效!");
		}
		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(PCPSUtil
						.getICNoByBranchNo(sysOpUser.getOperBranchNo()));
		// 计算费用
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_lock, ac.getCardNo(), null,
				issueCompany.getTranDate(), ac.getBalance());

		BigInteger fee = ifp.getFee();
		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_lock);

		// 设置返回余额
		clObj.balance = ac.getBalance();
		clObj.fee = fee;

		// 如果是试算,把试算结果返回
		if (clObj.isTrail) {
			return clObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !clObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}
		// 检查收费模式
		if (!PCPSUtil.compareObject(clObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(clObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");
		// 检查优惠的手续费
		if ((clObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(clObj.discountFee) > 0
				|| clObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (clObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(clObj.authOperId, clObj.authPwd, clObj.operId,
					sysOpUser.getOperBranchNo());
		else
			clObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(clObj.discountFee);
		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(clObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			clObj.cashFee = BigInteger.ZERO;
			clObj.cardFee = factfee;
		} else {
			clObj.cashFee = factfee;
			clObj.cardFee = BigInteger.ZERO;
		}
		ac
				.setManualLockStatus(ActivateCard.ACTIVATECARD_MANUALLOCKSTATUS_LOCKED);
		activateCardDaoImpl.update(ac);

		// 卡事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		String accSeqNo = null;

		// 如果需要延期,则执行扣费动作
		if (clObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = clObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = clObj.cardNo;
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = clObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "卡手工锁定手续费");
			// 保留流水号
			accSeqNo = paidResult.accseqno;
			// 设置返回余额
			clObj.balance = paidResult.cardbalance.get(clObj.cardNo);
		}

		// 现金收入记帐
		if (clObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					clObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid, clObj.operId,
					occurTime, "卡手工锁定手续费");

		// 业务单号
		String cardEventOrderSeq = pcpsCommonDaoImpl.getOrderNumber(occurTime,
				clObj.branchNo);
		clObj.orderSeqNo = evid.toString();// 返回的CardEventId

		// 4.记载卡事件日志
		CardEventLog cel = new CardEventLog();
		cel.setBalance(clObj.balance);
		cel.setFee(fee);
		cel.setCardFee(clObj.cardFee);
		cel.setCashFee(clObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(clObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(clObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(clObj.operId);
		cel.setRemark(clObj.remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(ac.getCardNo());
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setExpired(ac.getExpired());
		cel.setNewExpired(null);
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(occurTime);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_MANUAL_LOCK);
		cardEventLogDaoImpl.insert(cel);
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Edit, "卡手工锁定", "CardNo:" + cel.getCardNo());

		return clObj;
	}

	/**
	 * 解除卡手工锁定
	 */
	@Override
	public CardLossObject cardManualLockFree(PCPSWebInput webInput,
			CardLossObject clObj) throws PCPSApplicationException {
		// 1. 参数检查
		if (clObj == null || PCPSUtil.isEmpty(clObj.cardNo)
				|| clObj.operId == null || clObj.branchNo == null)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		// 2. 如果是执行业务操作,检查备注是否为空
		if (!clObj.isTrail && PCPSUtil.isEmpty(clObj.remark)) {
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		}
		// 3. 检查卡相关属性
		ActivateCard ac = activateCardDaoImpl
				.getActivateCardByCardNoForUpdate(clObj.cardNo);
		// 检查是否能交易
		isCardCanDoTrans(ac);
		// 检查销售机构日终状态
		checkSaleBranchDayOff(webInput.getOperBranchNo());

		// 判断卡状态
		if (ac.getLossStatus() != null
				&& (ac.getLossStatus().equals(
						ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED) || ac
						.getLossStatus()
						.equals(
								ActivateCard.ACTIVATECARD_LOSSSTATUS_TEMP_LOSSED))) {
			errException("操作失败,此卡" + clObj.cardNo + " 已挂失!");
		}
		if (!ac.getCloseStatus().equals(
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL)) {
			errException("操作失败,此卡" + clObj.cardNo + " 已销卡!");
		}
		if (ac.getManualLockStatus().equals(
				ActivateCard.ACTIVATECARD_MANUALLOCKSTATUS_LOCKED_FREE)
				|| ac.getManualLockStatus().equals(
						ActivateCard.ACTIVATECARD_MANUALLOCKSTATUS_UNLOCK)) {
			errException("操作失败,此卡" + clObj.cardNo + " 未锁定或已解除锁定!");
		}

		// 取当前时间
		Date occurTime = pcpsCommonDaoImpl.getDatabaseSysTime();
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(clObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo())) {
			errException("操作员无效!");
		}
		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(PCPSUtil
						.getICNoByBranchNo(sysOpUser.getOperBranchNo()));
		// 计算费用
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_lockFree, ac.getCardNo(),
				null, issueCompany.getTranDate(), ac.getBalance());

		BigInteger fee = ifp.getFee();
		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_lockFree);

		// 设置返回余额
		clObj.balance = ac.getBalance();
		clObj.fee = fee;

		// 如果是试算,把试算结果返回
		if (clObj.isTrail) {
			return clObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !clObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}
		// 检查收费模式
		if (!PCPSUtil.compareObject(clObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(clObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");
		// 检查优惠的手续费
		if ((clObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(clObj.discountFee) > 0
				|| clObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (clObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(clObj.authOperId, clObj.authPwd, clObj.operId,
					sysOpUser.getOperBranchNo());
		else
			clObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(clObj.discountFee);
		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(clObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			clObj.cashFee = BigInteger.ZERO;
			clObj.cardFee = factfee;
		} else {
			clObj.cashFee = factfee;
			clObj.cardFee = BigInteger.ZERO;
		}
		ac
				.setManualLockStatus(ActivateCard.ACTIVATECARD_MANUALLOCKSTATUS_LOCKED_FREE);
		activateCardDaoImpl.update(ac);

		// 卡事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		String accSeqNo = null;

		// 如果需要延期,则执行扣费动作
		if (clObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = clObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = clObj.cardNo;
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = clObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "解除卡手工锁定手续费");
			// 保留流水号
			accSeqNo = paidResult.accseqno;
			// 设置返回余额
			clObj.balance = paidResult.cardbalance.get(clObj.cardNo);
		}

		// 现金收入记帐
		if (clObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					clObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid, clObj.operId,
					occurTime, "解除卡手工锁定手续费");

		// 业务单号
		String cardEventOrderSeq = pcpsCommonDaoImpl.getOrderNumber(occurTime,
				clObj.branchNo);
		clObj.orderSeqNo = evid.toString();// 返回的CardEventId

		// 4.记载卡事件日志
		CardEventLog cel = new CardEventLog();
		cel.setBalance(clObj.balance);
		cel.setFee(fee);
		cel.setCardFee(clObj.cardFee);
		cel.setCashFee(clObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(clObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(clObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(clObj.operId);
		cel.setRemark(clObj.remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(ac.getCardNo());
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setExpired(ac.getExpired());
		cel.setNewExpired(null);
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(occurTime);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_MANUAL_LOCK_FREE);
		cardEventLogDaoImpl.insert(cel);
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Edit, "解除卡手工锁定", "CardNo:"
						+ cel.getCardNo());

		return clObj;
	}

	/**
	 * 卡补磁
	 * 
	 * @param webInput
	 * @param cmObj
	 * @return
	 * @throws PCPSApplicationException
	 */
	@Override
	public CardMagneticObject cardMagnetic(PCPSWebInput webInput,
			CardMagneticObject cmObj) throws PCPSApplicationException {
		// 1. 参数检查
		if (cmObj == null || PCPSUtil.isEmpty(cmObj.cardNo)
				|| cmObj.operId == null || cmObj.branchNo == null)
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		// 2. 如果是执行业务操作,检查备注是否为空
		if (!cmObj.isTrail && PCPSUtil.isEmpty(cmObj.remark)) {
			throw new CardTranApplicationException(
					CardTranApplicationException.ERRCODE_CATEGORY_APPLICATION,
					TuxedoRespCode.RC_INVALID,
					CardTranApplicationException.ERRMSG_INVALID_PARMS);
		}
		// 3. 检查卡相关属性
		ActivateCard ac = activateCardDaoImpl
				.getActivateCardByCardNoForUpdate(cmObj.cardNo);
		// 检查是否能交易
		isCardCanDoTrans(ac);
		// 检查销售机构日终状态
		checkSaleBranchDayOff(webInput.getOperBranchNo());

		// 判断卡状态
		if (ac.getLossStatus() != null
				&& (ac.getLossStatus().equals(
						ActivateCard.ACTIVATECARD_LOSSSTATUS_LOSSED) || ac
						.getLossStatus()
						.equals(
								ActivateCard.ACTIVATECARD_LOSSSTATUS_TEMP_LOSSED))) {
			errException("操作失败,此卡" + cmObj.cardNo + " 已挂失!");
		}
		if (!ac.getCloseStatus().equals(
				ActivateCard.ACTIVATECARD_CLOSESTATUS_NORMAL)) {
			errException("操作失败,此卡" + cmObj.cardNo + " 已销卡!");
		}

		// 取当前时间
		Date occurTime = pcpsCommonDaoImpl.getDatabaseSysTime();
		SysOpUser sysOpUser = sysOpUserDaoImpl
				.getSysOpUserByOperId(cmObj.operId);
		if (sysOpUser == null || PCPSUtil.isEmpty(sysOpUser.getOperBranchNo())) {
			errException("操作员无效!");
		}
		// 取发卡商信息
		IssueCompany issueCompany = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(PCPSUtil
						.getICNoByBranchNo(sysOpUser.getOperBranchNo()));
		// 计算费用
		IssueFeePolicy ifp = issueFeePolicyBusinessImpl.calcCardHolderFee(
				issueCompany.getIssueCompanyNo(), sysOpUser.getOperBranchNo(),
				IssueFeePolicy.IFPolicy_busiType_magnetic, ac.getCardNo(),
				null, issueCompany.getTranDate(), ac.getBalance());

		BigInteger fee = ifp.getFee();
		if (BigInteger.ZERO.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "手续费计算错!");

		// 取发卡商资费上下限
		fee = getIssuePolicyLimitFee(issueCompany.getIssueCompanyNo(), fee,
				IssueFeePolicy.IFPolicy_busiType_magnetic);

		// 设置返回余额
		cmObj.balance = ac.getBalance();
		cmObj.fee = fee;

		// 设置返回二三磁道内容
		cmObj.track2 = ac.getTwoTrackContent();
		cmObj.track3 = ac.getThirdTrackContent();

		// 如果是试算,把试算结果返回
		if (cmObj.isTrail) {
			return cmObj;
		} else {
			// 判断收费模式是否选择正确
			if (!IssueFeePolicy.IFPolicy_amountType_CashOrCard.equals(ifp
					.getAmountType())
					&& !cmObj.chargeMode.equals(ifp.getAmountType())) {
				throw new PCPSApplicationException("", "此业务资费的收费模式必须为"
						+ (IssueFeePolicy.IFPolicy_amountType_Cash.equals(ifp
								.getAmountType()) ? "[现金]!" : "[卡内扣]!"));
			}
		}
		// 检查收费模式
		if (!PCPSUtil.compareObject(cmObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)
				&& !PCPSUtil.compareObject(cmObj.chargeMode,
						ExtendExpiredObject.CHARGEMODE_CASH))
			throw new PCPSApplicationException("", "收费模式非法!");
		// 检查优惠的手续费
		if ((cmObj.discountFee == null)
				|| BigInteger.ZERO.compareTo(cmObj.discountFee) > 0
				|| cmObj.discountFee.compareTo(fee) > 0)
			throw new PCPSApplicationException("", "优惠的手续费非法!");

		// 如果存在手续费优惠,则检查授权操作员
		if (cmObj.discountFee.compareTo(BigInteger.ZERO) > 0)
			checkAuthOperId(cmObj.authOperId, cmObj.authPwd, cmObj.operId,
					sysOpUser.getOperBranchNo());
		else
			cmObj.authOperId = null;

		// 实收手续费
		BigInteger factfee = fee.subtract(cmObj.discountFee);
		// 如果扣费模式是卡内扣,置现金手续费为0
		if (PCPSUtil.compareObject(cmObj.chargeMode,
				ExtendExpiredObject.CHARGEMODE_CARDFEE)) {
			cmObj.cashFee = BigInteger.ZERO;
			cmObj.cardFee = factfee;
		} else {
			cmObj.cashFee = factfee;
			cmObj.cardFee = BigInteger.ZERO;
		}

		// 卡事件ID
		BigInteger evid = pcpsCommonDaoImpl.getUniqueIntegerKey();
		String accSeqNo = null;

		// 如果需要延期,则执行扣费动作
		if (cmObj.cardFee.compareTo(BigInteger.ZERO) > 0) {
			// 设置扣费参数
			PaidParam paidParam = new PaidParam();
			paidParam.issueCompanyNo = issueCompany.getIssueCompanyNo();
			paidParam.tranDate = issueCompany.getTranDate();
			paidParam.tranSeqNo = "CARDEV_" + evid.toString();
			paidParam.operId = cmObj.operId;
			ArrayList<PaidCardParam> accountParamList = new ArrayList<PaidCardParam>();
			PaidCardParam pcp = paidParam.new PaidCardParam();
			pcp.cardNo = cmObj.cardNo;
			pcp.pwd = null;
			pcp.amt = BigInteger.ZERO;
			pcp.fee = cmObj.cardFee;
			accountParamList.add(pcp);
			paidParam.allPaidCardList = accountParamList;

			// 执行扣费
			PaidResult paidResult = PaidFee(paidParam, "卡补磁手续费");
			// 保留流水号
			accSeqNo = paidResult.accseqno;
			// 设置返回余额
			cmObj.balance = paidResult.cardbalance.get(cmObj.cardNo);
		}

		// 现金收入记帐
		if (cmObj.cashFee.compareTo(BigInteger.ZERO) > 0)
			saleBranchCaptialAccount(sysOpUser.getOperBranchNo(), issueCompany
					.getTranDate(), BigInteger.ZERO, BigInteger.ZERO,
					cmObj.cashFee, BigInteger.ZERO,
					SaleCapitalDetail.TRANTYPE_RECEIVECASH, evid, cmObj.operId,
					occurTime, "卡补磁手续费");

		// 业务单号
		String cardEventOrderSeq = pcpsCommonDaoImpl.getOrderNumber(occurTime,
				cmObj.branchNo);
		cmObj.orderSeqNo = evid.toString();// 返回的CardEventId

		// 4.记载卡事件日志
		CardEventLog cel = new CardEventLog();
		cel.setBalance(cmObj.balance);
		cel.setFee(fee);
		cel.setCardFee(cmObj.cardFee);
		cel.setCashFee(cmObj.cashFee);
		cel.setFactFee(factfee);
		cel.setDiscountFee(cmObj.discountFee);
		cel.setFeeRatio(BigInteger.valueOf(ifp.getFixRatio()));
		cel.setAuthOperId(cmObj.authOperId);
		cel.setAccSeqNo(accSeqNo);
		cel.setOperId(cmObj.operId);
		cel.setRemark(cmObj.remark);
		cel.setCardEventId(evid);
		cel.setCardEventOrderSeq(cardEventOrderSeq);
		cel.setCardNo(ac.getCardNo());
		cel.setCardClassicId(ac.getCardClassicId());
		cel.setExpired(ac.getExpired());
		cel.setNewExpired(null);
		cel.setTranDate(issueCompany.getTranDate());
		cel.setTranTime(occurTime);
		cel.setMasterAccNo(ac.getMasterAccNo());
		cel.setIssueCompanyNo(issueCompany.getIssueCompanyNo());
		cel.setBranchNo(sysOpUser.getOperBranchNo());
		cel.setEventType(CardEventLog.CARDEVENTLOG_EVENTTYPE_MAGNETIC);
		cardEventLogDaoImpl.insert(cel);
		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Edit, "卡补磁", "CardNo:" + cel.getCardNo());

		return cmObj;
	}

}
